mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:17:14 +00:00
Cache flushing implementation for the task model.
R=brianwilkerson@google.com BUG= Review URL: https://codereview.chromium.org//1133513003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45597 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
parent
2a1657d467
commit
a3366361de
|
@ -6,16 +6,19 @@ library analyzer.src.context.cache;
|
|||
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart'
|
||||
show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority;
|
||||
import 'package:analyzer/src/generated/html.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/task/model.dart';
|
||||
|
||||
/**
|
||||
* Return `true` if the given [target] is a priority one.
|
||||
*/
|
||||
typedef bool IsPriorityAnalysisTarget(AnalysisTarget target);
|
||||
|
||||
/**
|
||||
* An LRU cache of results produced by analysis.
|
||||
*/
|
||||
|
@ -37,13 +40,11 @@ class AnalysisCache {
|
|||
* so the most specific partition (usually an [SdkCachePartition]) should be
|
||||
* first and the most general (usually a [UniversalCachePartition]) last.
|
||||
*/
|
||||
AnalysisCache(this._partitions);
|
||||
|
||||
/**
|
||||
* Return the number of entries in this cache that have an AST associated with
|
||||
* them.
|
||||
*/
|
||||
int get astSize => _partitions[_partitions.length - 1].astSize;
|
||||
AnalysisCache(this._partitions) {
|
||||
for (CachePartition partition in _partitions) {
|
||||
partition._cache = this;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(brianwilkerson) Implement or delete this.
|
||||
// /**
|
||||
|
@ -62,22 +63,6 @@ class AnalysisCache {
|
|||
// return data;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just read from
|
||||
* the cache.
|
||||
*/
|
||||
void accessedAst(AnalysisTarget target) {
|
||||
// TODO(brianwilkerson) Extract this logic to a helper method (here and
|
||||
// elsewhere)
|
||||
int count = _partitions.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_partitions[i].contains(target)) {
|
||||
_partitions[i].accessedAst(target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entry associated with the given [target].
|
||||
*/
|
||||
|
@ -135,8 +120,6 @@ class AnalysisCache {
|
|||
* Associate the given [entry] with the given [target].
|
||||
*/
|
||||
void put(AnalysisTarget target, CacheEntry entry) {
|
||||
entry._cache = this;
|
||||
entry._target = target;
|
||||
entry.fixExceptionState();
|
||||
int count = _partitions.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -177,20 +160,6 @@ class AnalysisCache {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just removed
|
||||
* from the cache.
|
||||
*/
|
||||
void removedAst(AnalysisTarget target) {
|
||||
int count = _partitions.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_partitions[i].contains(target)) {
|
||||
_partitions[i].removedAst(target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of targets that are mapped to cache entries.
|
||||
*/
|
||||
|
@ -203,20 +172,6 @@ class AnalysisCache {
|
|||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just stored to
|
||||
* the cache.
|
||||
*/
|
||||
void storedAst(AnalysisTarget target) {
|
||||
int count = _partitions.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (_partitions[i].contains(target)) {
|
||||
_partitions[i].storedAst(target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResultData _getDataFor(TargetedResult result) {
|
||||
AnalysisTarget target = result.target;
|
||||
int count = _partitions.length;
|
||||
|
@ -242,9 +197,9 @@ class CacheEntry {
|
|||
static int _EXPLICITLY_ADDED_FLAG = 0;
|
||||
|
||||
/**
|
||||
* The cache that contains this entry.
|
||||
* The partition that is responsible for this entry.
|
||||
*/
|
||||
AnalysisCache _cache;
|
||||
CachePartition _partition;
|
||||
|
||||
/**
|
||||
* The target this entry is about.
|
||||
|
@ -295,19 +250,6 @@ class CacheEntry {
|
|||
_setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if this entry contains at least one result whose value is an
|
||||
* AST structure.
|
||||
*/
|
||||
bool get hasAstStructure {
|
||||
for (ResultData data in _resultMap.values) {
|
||||
if (data.value is AstNode || data.value is XmlNode) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the state of the [exception] to match the current state of the entry.
|
||||
*/
|
||||
|
@ -317,19 +259,6 @@ class CacheEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark any AST structures associated with this cache entry as being flushed.
|
||||
*/
|
||||
void flushAstStructures() {
|
||||
_resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
|
||||
if (data.value is AstNode || data.value is XmlNode) {
|
||||
_validateStateChange(descriptor, CacheState.FLUSHED);
|
||||
data.state = CacheState.FLUSHED;
|
||||
data.value = descriptor.defaultValue;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the memento of the result represented by the given [descriptor].
|
||||
*/
|
||||
|
@ -361,6 +290,9 @@ class CacheEntry {
|
|||
if (data == null) {
|
||||
return descriptor.defaultValue;
|
||||
}
|
||||
if (_partition != null) {
|
||||
_partition.resultAccessed(_target, descriptor);
|
||||
}
|
||||
return data.value;
|
||||
}
|
||||
|
||||
|
@ -415,7 +347,7 @@ class CacheEntry {
|
|||
for (ResultDescriptor descriptor in descriptors) {
|
||||
ResultData data = _getResultData(descriptor);
|
||||
TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
||||
data.invalidate(_cache, thisResult, CacheState.ERROR);
|
||||
data.invalidate(_partition, thisResult, CacheState.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,7 +367,7 @@ class CacheEntry {
|
|||
ResultData data = _resultMap[descriptor];
|
||||
if (data != null) {
|
||||
TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
||||
data.invalidate(_cache, thisResult, CacheState.INVALID);
|
||||
data.invalidate(_partition, thisResult, CacheState.INVALID);
|
||||
}
|
||||
} else {
|
||||
ResultData data = _getResultData(descriptor);
|
||||
|
@ -458,12 +390,13 @@ class CacheEntry {
|
|||
/*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/
|
||||
value, List<TargetedResult> dependedOn, Object memento) {
|
||||
_validateStateChange(descriptor, CacheState.VALID);
|
||||
ResultData data = _getResultData(descriptor);
|
||||
{
|
||||
TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
||||
data.invalidate(_cache, thisResult, CacheState.INVALID);
|
||||
data.setDependedOnResults(_cache, thisResult, dependedOn);
|
||||
TargetedResult thisResult = new TargetedResult(_target, descriptor);
|
||||
if (_partition != null) {
|
||||
_partition.resultStored(thisResult, value);
|
||||
}
|
||||
ResultData data = _getResultData(descriptor);
|
||||
data.invalidate(_partition, thisResult, CacheState.INVALID);
|
||||
data.setDependedOnResults(_partition, thisResult, dependedOn);
|
||||
data.state = CacheState.VALID;
|
||||
data.value = value == null ? descriptor.defaultValue : value;
|
||||
data.memento = memento;
|
||||
|
@ -539,10 +472,147 @@ class CacheEntry {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that controls flushing of analysis results from the cache.
|
||||
*/
|
||||
class CacheFlushManager<T> {
|
||||
final IsPriorityAnalysisTarget isPriorityAnalysisTarget;
|
||||
final ResultCachingPolicy<T> policy;
|
||||
final int maxActiveSize;
|
||||
final int maxIdleSize;
|
||||
|
||||
/**
|
||||
* A map of the stored [TargetedResult] to their sizes.
|
||||
*/
|
||||
final HashMap<TargetedResult, int> resultSizeMap =
|
||||
new HashMap<TargetedResult, int>();
|
||||
|
||||
/**
|
||||
* A linked set containing the most recently accessed results with the most
|
||||
* recently used at the end of the list. When more results are added than the
|
||||
* maximum size allowed then the least recently used results will be flushed
|
||||
* from the cache.
|
||||
*/
|
||||
final LinkedHashSet<TargetedResult> recentlyUsed =
|
||||
new LinkedHashSet<TargetedResult>();
|
||||
|
||||
/**
|
||||
* The current size of stored results.
|
||||
*/
|
||||
int currentSize = 0;
|
||||
|
||||
/**
|
||||
* The current maximum cache size.
|
||||
*/
|
||||
int maxSize;
|
||||
|
||||
CacheFlushManager(
|
||||
ResultCachingPolicy<T> policy, this.isPriorityAnalysisTarget)
|
||||
: policy = policy,
|
||||
maxActiveSize = policy.maxActiveSize,
|
||||
maxIdleSize = policy.maxIdleSize,
|
||||
maxSize = policy.maxIdleSize;
|
||||
|
||||
/**
|
||||
* If [currentSize] is already less than [maxSize], returns an empty list.
|
||||
* Otherwise returns [TargetedResult]s to flush from the cache to make
|
||||
* [currentSize] less or equal to [maxSize].
|
||||
*
|
||||
* Results for priority files are never flushed, so this method might leave
|
||||
* [currentSize] greater than [maxSize].
|
||||
*/
|
||||
List<TargetedResult> flushToSize() {
|
||||
// If still under the cap, done.
|
||||
if (maxSize == -1 || currentSize <= maxSize) {
|
||||
return TargetedResult.EMPTY_LIST;
|
||||
}
|
||||
// Flush results until we are under the cap.
|
||||
List<TargetedResult> resultsToFlush = <TargetedResult>[];
|
||||
for (TargetedResult result in recentlyUsed) {
|
||||
if (isPriorityAnalysisTarget(result.target)) {
|
||||
continue;
|
||||
}
|
||||
resultsToFlush.add(result);
|
||||
int size = resultSizeMap.remove(result);
|
||||
assert(size != null);
|
||||
currentSize -= size;
|
||||
if (currentSize <= maxSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
recentlyUsed.removeAll(resultsToFlush);
|
||||
return resultsToFlush;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this manager that the corresponding analysis context is active.
|
||||
*/
|
||||
void madeActive() {
|
||||
maxSize = maxActiveSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this manager that the corresponding analysis context is idle.
|
||||
* Returns [TargetedResult]s that should be flushed from the cache.
|
||||
*/
|
||||
List<TargetedResult> madeIdle() {
|
||||
maxSize = maxIdleSize;
|
||||
return flushToSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the given [result] was just read from the cache.
|
||||
*/
|
||||
void resultAccessed(TargetedResult result) {
|
||||
if (recentlyUsed.remove(result)) {
|
||||
recentlyUsed.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the given [newResult] and [newValue] were stored to the cache.
|
||||
* Returns [TargetedResult]s that should be flushed from the cache.
|
||||
*/
|
||||
List<TargetedResult> resultStored(TargetedResult newResult, T newValue) {
|
||||
if (!recentlyUsed.remove(newResult)) {
|
||||
int size = policy.measure(newValue);
|
||||
resultSizeMap[newResult] = size;
|
||||
currentSize += size;
|
||||
}
|
||||
recentlyUsed.add(newResult);
|
||||
return flushToSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the given [target] was just removed from to the cache.
|
||||
*/
|
||||
void targetRemoved(AnalysisTarget target) {
|
||||
List<TargetedResult> resultsToRemove = <TargetedResult>[];
|
||||
for (TargetedResult result in recentlyUsed) {
|
||||
if (result.target == target) {
|
||||
resultsToRemove.add(result);
|
||||
int size = resultSizeMap.remove(result);
|
||||
assert(size != null);
|
||||
currentSize -= size;
|
||||
}
|
||||
}
|
||||
recentlyUsed.removeAll(resultsToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single partition in an LRU cache of information related to analysis.
|
||||
*/
|
||||
abstract class CachePartition {
|
||||
/**
|
||||
* The [AnalysisCache] that owns this partition.
|
||||
*
|
||||
* TODO(scheglov) It seems wrong. Partitions may be shared between caches.
|
||||
* But we need a way to go from every "enclosing" partition into "enclosed"
|
||||
* ones.
|
||||
*/
|
||||
AnalysisCache _cache;
|
||||
|
||||
/**
|
||||
* The context that owns this partition. Multiple contexts can reference a
|
||||
* partition, but only one context can own it.
|
||||
|
@ -550,15 +620,10 @@ abstract class CachePartition {
|
|||
final InternalAnalysisContext context;
|
||||
|
||||
/**
|
||||
* The maximum number of sources for which AST structures should be kept in
|
||||
* the cache.
|
||||
* A table mapping caching policies to the cache flush managers.
|
||||
*/
|
||||
int _maxCacheSize = 0;
|
||||
|
||||
/**
|
||||
* The policy used to determine which results to remove from the cache.
|
||||
*/
|
||||
final CacheRetentionPolicy _retentionPolicy;
|
||||
final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap =
|
||||
new HashMap<ResultCachingPolicy, CacheFlushManager>();
|
||||
|
||||
/**
|
||||
* A table mapping the targets belonging to this partition to the information
|
||||
|
@ -567,38 +632,11 @@ abstract class CachePartition {
|
|||
HashMap<AnalysisTarget, CacheEntry> _targetMap =
|
||||
new HashMap<AnalysisTarget, CacheEntry>();
|
||||
|
||||
/**
|
||||
* A list containing the most recently accessed targets with the most recently
|
||||
* used at the end of the list. When more targets are added than the maximum
|
||||
* allowed then the least recently used target will be removed and will have
|
||||
* it's cached AST structure flushed.
|
||||
*/
|
||||
List<AnalysisTarget> _recentlyUsed = <AnalysisTarget>[];
|
||||
|
||||
/**
|
||||
* Initialize a newly created cache partition, belonging to the given
|
||||
* [context]. The partition will maintain at most [_maxCacheSize] AST
|
||||
* structures in the cache, using the [_retentionPolicy] to determine which
|
||||
* AST structures to flush.
|
||||
* [context].
|
||||
*/
|
||||
CachePartition(this.context, this._maxCacheSize, this._retentionPolicy);
|
||||
|
||||
/**
|
||||
* Return the number of entries in this partition that have an AST associated
|
||||
* with them.
|
||||
*/
|
||||
int get astSize {
|
||||
int astSize = 0;
|
||||
int count = _recentlyUsed.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
AnalysisTarget target = _recentlyUsed[i];
|
||||
CacheEntry entry = _targetMap[target];
|
||||
if (entry.hasAstStructure) {
|
||||
astSize++;
|
||||
}
|
||||
}
|
||||
return astSize;
|
||||
}
|
||||
CachePartition(this.context);
|
||||
|
||||
/**
|
||||
* Return a table mapping the targets known to the context to the information
|
||||
|
@ -609,40 +647,6 @@ abstract class CachePartition {
|
|||
*/
|
||||
Map<AnalysisTarget, CacheEntry> get map => _targetMap;
|
||||
|
||||
/**
|
||||
* Return the maximum size of the cache.
|
||||
*/
|
||||
int get maxCacheSize => _maxCacheSize;
|
||||
|
||||
/**
|
||||
* Set the maximum size of the cache to the given [size].
|
||||
*/
|
||||
void set maxCacheSize(int size) {
|
||||
_maxCacheSize = size;
|
||||
while (_recentlyUsed.length > _maxCacheSize) {
|
||||
if (!_flushAstFromCache()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just read from
|
||||
* the cache.
|
||||
*/
|
||||
void accessedAst(AnalysisTarget target) {
|
||||
if (_recentlyUsed.remove(target)) {
|
||||
_recentlyUsed.add(target);
|
||||
return;
|
||||
}
|
||||
while (_recentlyUsed.length >= _maxCacheSize) {
|
||||
if (!_flushAstFromCache()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_recentlyUsed.add(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if the given [target] is contained in this partition.
|
||||
*/
|
||||
|
@ -666,6 +670,12 @@ abstract class CachePartition {
|
|||
* Associate the given [entry] with the given [target].
|
||||
*/
|
||||
void put(AnalysisTarget target, CacheEntry entry) {
|
||||
if (entry._partition != null) {
|
||||
throw new StateError(
|
||||
'The entry for $target is already in ${entry._partition}');
|
||||
}
|
||||
entry._partition = this;
|
||||
entry._target = target;
|
||||
entry.fixExceptionState();
|
||||
_targetMap[target] = entry;
|
||||
}
|
||||
|
@ -674,16 +684,34 @@ abstract class CachePartition {
|
|||
* Remove all information related to the given [target] from this cache.
|
||||
*/
|
||||
void remove(AnalysisTarget target) {
|
||||
_recentlyUsed.remove(target);
|
||||
for (CacheFlushManager flushManager in _flushManagerMap.values) {
|
||||
flushManager.targetRemoved(target);
|
||||
}
|
||||
_targetMap.remove(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just removed
|
||||
* from the cache.
|
||||
* Records that a value of the result described by the given [descriptor]
|
||||
* for the given [target] was just read from the cache.
|
||||
*/
|
||||
void removedAst(AnalysisTarget target) {
|
||||
_recentlyUsed.remove(target);
|
||||
void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) {
|
||||
CacheFlushManager flushManager = _getFlushManager(descriptor);
|
||||
TargetedResult result = new TargetedResult(target, descriptor);
|
||||
flushManager.resultAccessed(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records that the given [result] was just stored into the cache.
|
||||
*/
|
||||
void resultStored(TargetedResult result, Object value) {
|
||||
CacheFlushManager flushManager = _getFlushManager(result.result);
|
||||
List<TargetedResult> resultsToFlush =
|
||||
flushManager.resultStored(result, value);
|
||||
for (TargetedResult result in resultsToFlush) {
|
||||
CacheEntry entry = get(result.target);
|
||||
ResultData data = entry._resultMap[result.result];
|
||||
data.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -691,123 +719,21 @@ abstract class CachePartition {
|
|||
*/
|
||||
int size() => _targetMap.length;
|
||||
|
||||
/**
|
||||
* Record that the AST associated with the given [target] was just stored to
|
||||
* the cache.
|
||||
*/
|
||||
void storedAst(AnalysisTarget target) {
|
||||
if (_recentlyUsed.contains(target)) {
|
||||
return;
|
||||
}
|
||||
while (_recentlyUsed.length >= _maxCacheSize) {
|
||||
if (!_flushAstFromCache()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_recentlyUsed.add(target);
|
||||
ResultData _getDataFor(TargetedResult result) {
|
||||
return _cache._getDataFor(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to flush one AST structure from the cache. Return `true` if a
|
||||
* structure was flushed.
|
||||
* Return the [CacheFlushManager] for the given [descriptor], not `null`.
|
||||
*/
|
||||
bool _flushAstFromCache() {
|
||||
AnalysisTarget removedTarget = _removeAstToFlush();
|
||||
if (removedTarget == null) {
|
||||
return false;
|
||||
}
|
||||
CacheEntry entry = _targetMap[removedTarget];
|
||||
entry.flushAstStructures();
|
||||
return true;
|
||||
CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
|
||||
ResultCachingPolicy policy = descriptor.cachingPolicy;
|
||||
return _flushManagerMap.putIfAbsent(
|
||||
policy, () => new CacheFlushManager(policy, _isPriorityAnalysisTarget));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove and return one target from the list of recently used targets whose
|
||||
* AST structure can be flushed from the cache, or `null` if none of the
|
||||
* targets can be removed. The target that will be returned will be the target
|
||||
* that has been unreferenced for the longest period of time but that is not a
|
||||
* priority for analysis.
|
||||
*/
|
||||
AnalysisTarget _removeAstToFlush() {
|
||||
int targetToRemove = -1;
|
||||
for (int i = 0; i < _recentlyUsed.length; i++) {
|
||||
AnalysisTarget target = _recentlyUsed[i];
|
||||
RetentionPriority priority =
|
||||
_retentionPolicy.getAstPriority(target, _targetMap[target]);
|
||||
if (priority == RetentionPriority.LOW) {
|
||||
return _recentlyUsed.removeAt(i);
|
||||
} else if (priority == RetentionPriority.MEDIUM && targetToRemove < 0) {
|
||||
targetToRemove = i;
|
||||
}
|
||||
}
|
||||
if (targetToRemove < 0) {
|
||||
// This happens if the retention policy returns a priority of HIGH for all
|
||||
// of the targets that have been recently used. This is the case, for
|
||||
// example, when the list of priority sources is bigger than the current
|
||||
// cache size.
|
||||
return null;
|
||||
}
|
||||
return _recentlyUsed.removeAt(targetToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A policy objecy that determines how important it is for data to be retained
|
||||
* in the analysis cache.
|
||||
*/
|
||||
abstract class CacheRetentionPolicy {
|
||||
/**
|
||||
* Return the priority of retaining the AST structure for the given [target]
|
||||
* in the given [entry].
|
||||
*/
|
||||
// TODO(brianwilkerson) Find a more general mechanism, probably based on task
|
||||
// descriptors, to determine which data is still needed for analysis and which
|
||||
// can be removed from the cache. Ideally we could (a) remove the need for
|
||||
// this class and (b) be able to flush all result data (not just AST's).
|
||||
RetentionPriority getAstPriority(AnalysisTarget target, CacheEntry entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* A retention policy that will keep AST's in the cache if there is analysis
|
||||
* information that needs to be computed for a source, where the computation is
|
||||
* dependent on having the AST.
|
||||
*/
|
||||
class DefaultRetentionPolicy implements CacheRetentionPolicy {
|
||||
/**
|
||||
* An instance of this class that can be shared.
|
||||
*/
|
||||
static const DefaultRetentionPolicy POLICY = const DefaultRetentionPolicy();
|
||||
|
||||
/**
|
||||
* Initialize a newly created instance of this class.
|
||||
*/
|
||||
const DefaultRetentionPolicy();
|
||||
|
||||
// TODO(brianwilkerson) Implement or delete this.
|
||||
// /**
|
||||
// * Return `true` if there is analysis information in the given entry that needs to be
|
||||
// * computed, where the computation is dependent on having the AST.
|
||||
// *
|
||||
// * @param dartEntry the entry being tested
|
||||
// * @return `true` if there is analysis information that needs to be computed from the AST
|
||||
// */
|
||||
// bool astIsNeeded(DartEntry dartEntry) =>
|
||||
// dartEntry.hasInvalidData(DartEntry.HINTS) ||
|
||||
// dartEntry.hasInvalidData(DartEntry.LINTS) ||
|
||||
// dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) ||
|
||||
// dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS);
|
||||
|
||||
@override
|
||||
RetentionPriority getAstPriority(AnalysisTarget target, CacheEntry entry) {
|
||||
// TODO(brianwilkerson) Implement or replace this.
|
||||
// if (sourceEntry is DartEntry) {
|
||||
// DartEntry dartEntry = sourceEntry;
|
||||
// if (astIsNeeded(dartEntry)) {
|
||||
// return RetentionPriority.MEDIUM;
|
||||
// }
|
||||
// }
|
||||
// return RetentionPriority.LOW;
|
||||
return RetentionPriority.MEDIUM;
|
||||
bool _isPriorityAnalysisTarget(AnalysisTarget target) {
|
||||
return context.priorityTargets.contains(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,12 +791,20 @@ class ResultData {
|
|||
dependentResults.add(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush this value.
|
||||
*/
|
||||
void flush() {
|
||||
state = CacheState.FLUSHED;
|
||||
value = descriptor.defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate this [ResultData] that corresponds to [thisResult] and
|
||||
* propagate invalidation to the results that depend on this one.
|
||||
*/
|
||||
void invalidate(
|
||||
AnalysisCache cache, TargetedResult thisResult, CacheState newState) {
|
||||
void invalidate(CachePartition partition, TargetedResult thisResult,
|
||||
CacheState newState) {
|
||||
// Invalidate this result.
|
||||
state = newState;
|
||||
value = descriptor.defaultValue;
|
||||
|
@ -878,15 +812,15 @@ class ResultData {
|
|||
List<TargetedResult> dependedOnResults = this.dependedOnResults;
|
||||
this.dependedOnResults = <TargetedResult>[];
|
||||
dependedOnResults.forEach((TargetedResult dependedOnResult) {
|
||||
ResultData data = cache._getDataFor(dependedOnResult);
|
||||
ResultData data = partition._getDataFor(dependedOnResult);
|
||||
data.removeDependentResult(thisResult);
|
||||
});
|
||||
// Invalidate results that depend on this result.
|
||||
List<TargetedResult> dependentResults = this.dependentResults;
|
||||
this.dependentResults = <TargetedResult>[];
|
||||
dependentResults.forEach((TargetedResult dependentResult) {
|
||||
ResultData data = cache._getDataFor(dependentResult);
|
||||
data.invalidate(cache, dependentResult, newState);
|
||||
ResultData data = partition._getDataFor(dependentResult);
|
||||
data.invalidate(partition, dependentResult, newState);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -900,15 +834,15 @@ class ResultData {
|
|||
/**
|
||||
* Set the [dependedOn] on which this result depends.
|
||||
*/
|
||||
void setDependedOnResults(AnalysisCache cache, TargetedResult thisResult,
|
||||
void setDependedOnResults(CachePartition partition, TargetedResult thisResult,
|
||||
List<TargetedResult> dependedOn) {
|
||||
dependedOnResults.forEach((TargetedResult dependedOnResult) {
|
||||
ResultData data = cache._getDataFor(dependedOnResult);
|
||||
ResultData data = partition._getDataFor(dependedOnResult);
|
||||
data.removeDependentResult(thisResult);
|
||||
});
|
||||
dependedOnResults = dependedOn;
|
||||
dependedOnResults.forEach((TargetedResult dependentResult) {
|
||||
ResultData data = cache._getDataFor(dependentResult);
|
||||
ResultData data = partition._getDataFor(dependentResult);
|
||||
data.addDependentResult(thisResult);
|
||||
});
|
||||
}
|
||||
|
@ -920,11 +854,9 @@ class ResultData {
|
|||
class SdkCachePartition extends CachePartition {
|
||||
/**
|
||||
* Initialize a newly created cache partition, belonging to the given
|
||||
* [context]. The partition will maintain at most [maxCacheSize] AST
|
||||
* structures in the cache.
|
||||
* [context].
|
||||
*/
|
||||
SdkCachePartition(InternalAnalysisContext context, int maxCacheSize)
|
||||
: super(context, maxCacheSize, DefaultRetentionPolicy.POLICY);
|
||||
SdkCachePartition(InternalAnalysisContext context) : super(context);
|
||||
|
||||
@override
|
||||
bool contains(AnalysisTarget target) {
|
||||
|
@ -979,13 +911,9 @@ class TargetedResult {
|
|||
class UniversalCachePartition extends CachePartition {
|
||||
/**
|
||||
* Initialize a newly created cache partition, belonging to the given
|
||||
* [context]. The partition will maintain at most [maxCacheSize] AST
|
||||
* structures in the cache, using the [retentionPolicy] to determine which
|
||||
* AST structures to flush.
|
||||
* [context].
|
||||
*/
|
||||
UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize,
|
||||
CacheRetentionPolicy retentionPolicy)
|
||||
: super(context, maxCacheSize, retentionPolicy);
|
||||
UniversalCachePartition(InternalAnalysisContext context) : super(context);
|
||||
|
||||
@override
|
||||
bool contains(AnalysisTarget target) => true;
|
||||
|
|
|
@ -181,9 +181,7 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
* Initialize a newly created analysis context.
|
||||
*/
|
||||
AnalysisContextImpl() {
|
||||
_privatePartition = new cache.UniversalCachePartition(this,
|
||||
AnalysisOptionsImpl.DEFAULT_CACHE_SIZE,
|
||||
new ContextRetentionPolicy(this));
|
||||
_privatePartition = new cache.UniversalCachePartition(this);
|
||||
_cache = createCacheFromSourceFactory(null);
|
||||
_taskManager = AnalysisEngine.instance.taskManager;
|
||||
_driver = new AnalysisDriver(_taskManager, this);
|
||||
|
@ -210,7 +208,6 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
int cacheSize = options.cacheSize;
|
||||
if (this._options.cacheSize != cacheSize) {
|
||||
this._options.cacheSize = cacheSize;
|
||||
_privatePartition.maxCacheSize = cacheSize;
|
||||
}
|
||||
this._options.analyzeFunctionBodiesPredicate =
|
||||
options.analyzeFunctionBodiesPredicate;
|
||||
|
@ -369,7 +366,8 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
bool hintsEnabled = _options.hint;
|
||||
bool lintsEnabled = _options.lint;
|
||||
|
||||
MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _privatePartition.iterator();
|
||||
MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
|
||||
_privatePartition.iterator();
|
||||
while (iterator.moveNext()) {
|
||||
AnalysisTarget target = iterator.key;
|
||||
if (target is Source) {
|
||||
|
@ -841,7 +839,8 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
return <Source>[source];
|
||||
} else if (kind == SourceKind.PART) {
|
||||
List<Source> libraries = <Source>[];
|
||||
MapIterator<AnalysisTarget, cache.CacheEntry> iterator = _cache.iterator();
|
||||
MapIterator<AnalysisTarget, cache.CacheEntry> iterator =
|
||||
_cache.iterator();
|
||||
while (iterator.moveNext()) {
|
||||
AnalysisTarget target = iterator.key;
|
||||
if (target is Source && getKindOf(target) == SourceKind.LIBRARY) {
|
||||
|
@ -1964,57 +1963,11 @@ class AnalysisContextImpl implements InternalAnalysisContext {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A retention policy used by an analysis context.
|
||||
*/
|
||||
class ContextRetentionPolicy implements cache.CacheRetentionPolicy {
|
||||
/**
|
||||
* The context associated with this policy.
|
||||
*/
|
||||
final AnalysisContextImpl context;
|
||||
|
||||
/**
|
||||
* Initialize a newly created policy to be associated with the given
|
||||
* [context].
|
||||
*/
|
||||
ContextRetentionPolicy(this.context);
|
||||
|
||||
@override
|
||||
RetentionPriority getAstPriority(
|
||||
AnalysisTarget target, cache.CacheEntry entry) {
|
||||
int priorityCount = context._priorityOrder.length;
|
||||
for (int i = 0; i < priorityCount; i++) {
|
||||
if (target == context._priorityOrder[i]) {
|
||||
return RetentionPriority.HIGH;
|
||||
}
|
||||
}
|
||||
if (_astIsNeeded(entry)) {
|
||||
return RetentionPriority.MEDIUM;
|
||||
}
|
||||
return RetentionPriority.LOW;
|
||||
}
|
||||
|
||||
bool _astIsNeeded(cache.CacheEntry entry) =>
|
||||
entry.isInvalid(BUILD_FUNCTION_TYPE_ALIASES_ERRORS) ||
|
||||
entry.isInvalid(BUILD_LIBRARY_ERRORS) ||
|
||||
entry.isInvalid(CONSTRUCTORS_ERRORS) ||
|
||||
entry.isInvalid(HINTS) ||
|
||||
//entry.isInvalid(LINTS) ||
|
||||
entry.isInvalid(RESOLVE_REFERENCES_ERRORS) ||
|
||||
entry.isInvalid(RESOLVE_TYPE_NAMES_ERRORS) ||
|
||||
entry.isInvalid(VERIFY_ERRORS);
|
||||
}
|
||||
|
||||
/**
|
||||
* An object that manages the partitions that can be shared between analysis
|
||||
* contexts.
|
||||
*/
|
||||
class PartitionManager {
|
||||
/**
|
||||
* The default cache size for a Dart SDK partition.
|
||||
*/
|
||||
static int _DEFAULT_SDK_CACHE_SIZE = 256;
|
||||
|
||||
/**
|
||||
* A table mapping SDK's to the partitions used for those SDK's.
|
||||
*/
|
||||
|
@ -2042,8 +1995,7 @@ class PartitionManager {
|
|||
// Check cache for an existing partition.
|
||||
cache.SdkCachePartition partition = _sdkPartitions[sdk];
|
||||
if (partition == null) {
|
||||
partition =
|
||||
new cache.SdkCachePartition(sdkContext, _DEFAULT_SDK_CACHE_SIZE);
|
||||
partition = new cache.SdkCachePartition(sdkContext);
|
||||
_sdkPartitions[sdk] = partition;
|
||||
}
|
||||
return partition;
|
||||
|
|
|
@ -20,10 +20,17 @@ import 'package:analyzer/src/generated/sdk.dart';
|
|||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/task/general.dart';
|
||||
import 'package:analyzer/src/task/incremental_element_builder.dart';
|
||||
import 'package:analyzer/src/task/model.dart';
|
||||
import 'package:analyzer/task/dart.dart';
|
||||
import 'package:analyzer/task/general.dart';
|
||||
import 'package:analyzer/task/model.dart';
|
||||
|
||||
/**
|
||||
* The [ResultCachingPolicy] for ASTs.
|
||||
*/
|
||||
const ResultCachingPolicy AST_CACHING_POLICY =
|
||||
const SimpleResultCachingPolicy(256, 64);
|
||||
|
||||
/**
|
||||
* The errors produced while resolving a library directives.
|
||||
*
|
||||
|
@ -64,7 +71,8 @@ final ResultDescriptor<List<AnalysisError>> BUILD_LIBRARY_ERRORS =
|
|||
* The [ClassElement]s of a [LibrarySpecificUnit].
|
||||
*/
|
||||
final ListResultDescriptor<ClassElement> CLASS_ELEMENTS =
|
||||
new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null);
|
||||
new ListResultDescriptor<ClassElement>('CLASS_ELEMENTS', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The element model associated with a single compilation unit.
|
||||
|
@ -73,7 +81,8 @@ final ListResultDescriptor<ClassElement> CLASS_ELEMENTS =
|
|||
*/
|
||||
final ResultDescriptor<CompilationUnitElement> COMPILATION_UNIT_ELEMENT =
|
||||
new ResultDescriptor<CompilationUnitElement>(
|
||||
'COMPILATION_UNIT_ELEMENT', null);
|
||||
'COMPILATION_UNIT_ELEMENT', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The [ConstructorElement]s of a [ClassElement].
|
||||
|
@ -92,6 +101,12 @@ final ResultDescriptor<List<AnalysisError>> CONSTRUCTORS_ERRORS =
|
|||
new ResultDescriptor<List<AnalysisError>>(
|
||||
'CONSTRUCTORS_ERRORS', AnalysisError.NO_ERRORS);
|
||||
|
||||
/**
|
||||
* The [ResultCachingPolicy] for [Element]s.
|
||||
*/
|
||||
const ResultCachingPolicy ELEMENT_CACHING_POLICY =
|
||||
const SimpleResultCachingPolicy(-1, -1);
|
||||
|
||||
/**
|
||||
* The sources representing the export closure of a library.
|
||||
* The [Source]s include only library sources, not their units.
|
||||
|
@ -130,7 +145,8 @@ final ListResultDescriptor<Source> IMPORT_SOURCE_CLOSURE =
|
|||
* The result is only available for targets representing a Dart library.
|
||||
*/
|
||||
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT1 =
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT1', null);
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT1', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partial [LibraryElement] associated with a library.
|
||||
|
@ -141,7 +157,8 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT1 =
|
|||
* The result is only available for targets representing a Dart library.
|
||||
*/
|
||||
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT2 =
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT2', null);
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT2', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partial [LibraryElement] associated with a library.
|
||||
|
@ -151,7 +168,8 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT2 =
|
|||
* The result is only available for targets representing a Dart library.
|
||||
*/
|
||||
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT3 =
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT3', null);
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT3', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partial [LibraryElement] associated with a library.
|
||||
|
@ -165,7 +183,8 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT3 =
|
|||
* The result is only available for targets representing a Dart library.
|
||||
*/
|
||||
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT4 =
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT4', null);
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT4', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partial [LibraryElement] associated with a library.
|
||||
|
@ -175,7 +194,8 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT4 =
|
|||
* The result is only available for targets representing a Dart library.
|
||||
*/
|
||||
final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT5 =
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null);
|
||||
new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT5', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The errors produced while parsing a compilation unit.
|
||||
|
@ -220,7 +240,8 @@ final ResultDescriptor<List<AnalysisError>> RESOLVE_TYPE_NAMES_ERRORS =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT1 =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT1', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT1', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partially resolved [CompilationUnit] associated with a unit.
|
||||
|
@ -230,7 +251,8 @@ final ResultDescriptor<CompilationUnit> RESOLVED_UNIT1 =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT2 =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT2', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT2', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partially resolved [CompilationUnit] associated with a unit.
|
||||
|
@ -240,7 +262,8 @@ final ResultDescriptor<CompilationUnit> RESOLVED_UNIT2 =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT3 =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT3', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT3', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partially resolved [CompilationUnit] associated with a unit.
|
||||
|
@ -250,7 +273,8 @@ final ResultDescriptor<CompilationUnit> RESOLVED_UNIT3 =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT4 =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT4', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The partially resolved [CompilationUnit] associated with a unit.
|
||||
|
@ -260,7 +284,8 @@ final ResultDescriptor<CompilationUnit> RESOLVED_UNIT4 =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT5 =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT5', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The errors produced while scanning a compilation unit.
|
||||
|
@ -273,6 +298,12 @@ final ResultDescriptor<List<AnalysisError>> SCAN_ERRORS =
|
|||
new ResultDescriptor<List<AnalysisError>>(
|
||||
'SCAN_ERRORS', AnalysisError.NO_ERRORS, contributesTo: DART_ERRORS);
|
||||
|
||||
/**
|
||||
* The [ResultCachingPolicy] for [TOKEN_STREAM].
|
||||
*/
|
||||
const ResultCachingPolicy TOKEN_STREAM_CACHING_POLICY =
|
||||
const SimpleResultCachingPolicy(1, 1);
|
||||
|
||||
/**
|
||||
* The [TypeProvider] of the context.
|
||||
*/
|
||||
|
@ -283,13 +314,15 @@ final ResultDescriptor<TypeProvider> TYPE_PROVIDER =
|
|||
* The [UsedImportedElements] of a [LibrarySpecificUnit].
|
||||
*/
|
||||
final ResultDescriptor<UsedImportedElements> USED_IMPORTED_ELEMENTS =
|
||||
new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null);
|
||||
new ResultDescriptor<UsedImportedElements>('USED_IMPORTED_ELEMENTS', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The [UsedLocalElements] of a [LibrarySpecificUnit].
|
||||
*/
|
||||
final ResultDescriptor<UsedLocalElements> USED_LOCAL_ELEMENTS =
|
||||
new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null);
|
||||
new ResultDescriptor<UsedLocalElements>('USED_LOCAL_ELEMENTS', null,
|
||||
cachingPolicy: ELEMENT_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The errors produced while verifying a compilation unit.
|
||||
|
|
|
@ -8,6 +8,12 @@ import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
|
|||
import 'package:analyzer/src/task/inputs.dart';
|
||||
import 'package:analyzer/task/model.dart';
|
||||
|
||||
/**
|
||||
* The default [ResultCachingPolicy], results are never flushed.
|
||||
*/
|
||||
const ResultCachingPolicy DEFAULT_CACHING_POLICY =
|
||||
const SimpleResultCachingPolicy(-1, -1);
|
||||
|
||||
/**
|
||||
* A concrete implementation of a [CompositeResultDescriptor].
|
||||
*/
|
||||
|
@ -42,8 +48,10 @@ class ListResultDescriptorImpl<E> extends ResultDescriptorImpl<List<E>>
|
|||
* contribute to it.
|
||||
*/
|
||||
ListResultDescriptorImpl(String name, List<E> defaultValue,
|
||||
{CompositeResultDescriptor contributesTo})
|
||||
: super(name, defaultValue, contributesTo: contributesTo);
|
||||
{CompositeResultDescriptor contributesTo,
|
||||
ResultCachingPolicy<List<E>> cachingPolicy: DEFAULT_CACHING_POLICY})
|
||||
: super(name, defaultValue,
|
||||
contributesTo: contributesTo, cachingPolicy: cachingPolicy);
|
||||
|
||||
@override
|
||||
ListTaskInput<E> of(AnalysisTarget target) =>
|
||||
|
@ -64,13 +72,19 @@ class ResultDescriptorImpl<V> implements ResultDescriptor<V> {
|
|||
*/
|
||||
final V defaultValue;
|
||||
|
||||
/**
|
||||
* The caching policy for results described by this descriptor.
|
||||
*/
|
||||
final ResultCachingPolicy<V> cachingPolicy;
|
||||
|
||||
/**
|
||||
* Initialize a newly created analysis result to have the given [name] and
|
||||
* [defaultValue]. If a composite result is specified, then this result will
|
||||
* contribute to it.
|
||||
*/
|
||||
ResultDescriptorImpl(this.name, this.defaultValue,
|
||||
{CompositeResultDescriptor contributesTo}) {
|
||||
{CompositeResultDescriptor contributesTo,
|
||||
this.cachingPolicy: DEFAULT_CACHING_POLICY}) {
|
||||
if (contributesTo is CompositeResultDescriptorImpl) {
|
||||
contributesTo.recordContributor(this);
|
||||
}
|
||||
|
@ -84,6 +98,23 @@ class ResultDescriptorImpl<V> implements ResultDescriptor<V> {
|
|||
String toString() => name;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple [ResultCachingPolicy] implementation that consider all the objects
|
||||
* to be of the size `1`.
|
||||
*/
|
||||
class SimpleResultCachingPolicy<T> implements ResultCachingPolicy<T> {
|
||||
@override
|
||||
final int maxActiveSize;
|
||||
|
||||
@override
|
||||
final int maxIdleSize;
|
||||
|
||||
const SimpleResultCachingPolicy(this.maxActiveSize, this.maxIdleSize);
|
||||
|
||||
@override
|
||||
int measure(T object) => 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* A concrete implementation of a [TaskDescriptor].
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:analyzer/src/generated/error.dart';
|
|||
import 'package:analyzer/src/generated/scanner.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/generated/utilities_general.dart';
|
||||
import 'package:analyzer/src/task/dart.dart';
|
||||
import 'package:analyzer/task/model.dart';
|
||||
|
||||
/**
|
||||
|
@ -102,7 +103,8 @@ final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT =
|
|||
* The result is only available for targets representing a Dart compilation unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> PARSED_UNIT =
|
||||
new ResultDescriptor<CompilationUnit>('PARSED_UNIT', null);
|
||||
new ResultDescriptor<CompilationUnit>('PARSED_UNIT', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The resolved [CompilationUnit] associated with a unit.
|
||||
|
@ -110,7 +112,8 @@ final ResultDescriptor<CompilationUnit> PARSED_UNIT =
|
|||
* The result is only available for targets representing a unit.
|
||||
*/
|
||||
final ResultDescriptor<CompilationUnit> RESOLVED_UNIT =
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT', null);
|
||||
new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT', null,
|
||||
cachingPolicy: AST_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The token stream produced while scanning a compilation unit.
|
||||
|
@ -120,8 +123,8 @@ final ResultDescriptor<CompilationUnit> RESOLVED_UNIT =
|
|||
*
|
||||
* The result is only available for targets representing a Dart compilation unit.
|
||||
*/
|
||||
final ResultDescriptor<Token> TOKEN_STREAM =
|
||||
new ResultDescriptor<Token>('TOKEN_STREAM', null);
|
||||
final ResultDescriptor<Token> TOKEN_STREAM = new ResultDescriptor<Token>(
|
||||
'TOKEN_STREAM', null, cachingPolicy: TOKEN_STREAM_CACHING_POLICY);
|
||||
|
||||
/**
|
||||
* The sources of the Dart files that a library consists of.
|
||||
|
|
|
@ -279,7 +279,8 @@ abstract class ListResultDescriptor<E> implements ResultDescriptor<List<E>> {
|
|||
* composite result is specified, then this result will contribute to it.
|
||||
*/
|
||||
factory ListResultDescriptor(String name, List<E> defaultValue,
|
||||
{CompositeResultDescriptor<List<E>> contributesTo}) = ListResultDescriptorImpl<E>;
|
||||
{CompositeResultDescriptor<List<E>> contributesTo,
|
||||
ResultCachingPolicy<List<E>> cachingPolicy}) = ListResultDescriptorImpl<E>;
|
||||
|
||||
@override
|
||||
ListTaskInput<E> of(AnalysisTarget target);
|
||||
|
@ -337,6 +338,32 @@ abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
|
|||
BinaryFunction<K, dynamic /*element of V*/, dynamic /*<E>*/ > mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* A policy object that can compute sizes of results and provide the maximum
|
||||
* active and idle sizes that can be kept in the cache.
|
||||
*
|
||||
* All the [ResultDescriptor]s with the same [ResultCachingPolicy] instance
|
||||
* share the same total size in a cache.
|
||||
*/
|
||||
abstract class ResultCachingPolicy<T> {
|
||||
/**
|
||||
* Return the maximum total size of results that can be kept in the cache
|
||||
* while analysis is in progress.
|
||||
*/
|
||||
int get maxActiveSize;
|
||||
|
||||
/**
|
||||
* Return the maximum total size of results that can be kept in the cache
|
||||
* while analysis is idle.
|
||||
*/
|
||||
int get maxIdleSize;
|
||||
|
||||
/**
|
||||
* Return the size of the given [object].
|
||||
*/
|
||||
int measure(T object);
|
||||
}
|
||||
|
||||
/**
|
||||
* A description of an analysis result that can be computed by an [AnalysisTask].
|
||||
*
|
||||
|
@ -346,9 +373,19 @@ abstract class ResultDescriptor<V> {
|
|||
/**
|
||||
* Initialize a newly created analysis result to have the given [name]. If a
|
||||
* composite result is specified, then this result will contribute to it.
|
||||
*
|
||||
* The given [cachingPolicy] is used to limit the total size of results
|
||||
* described by this descriptor. If no policy is specified, the results are
|
||||
* never evicted from the cache, and removed only when they are invalidated.
|
||||
*/
|
||||
factory ResultDescriptor(String name, V defaultValue,
|
||||
{CompositeResultDescriptor<V> contributesTo}) = ResultDescriptorImpl;
|
||||
{CompositeResultDescriptor<V> contributesTo,
|
||||
ResultCachingPolicy<V> cachingPolicy}) = ResultDescriptorImpl;
|
||||
|
||||
/**
|
||||
* Return the caching policy for results described by this descriptor.
|
||||
*/
|
||||
ResultCachingPolicy<V> get cachingPolicy;
|
||||
|
||||
/**
|
||||
* Return the default value for results described by this descriptor.
|
||||
|
|
|
@ -5485,6 +5485,7 @@ class TestAnalysisContext implements InternalAnalysisContext {
|
|||
fail("Unexpected invocation of getPrioritySources");
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
List<AnalysisTarget> get priorityTargets {
|
||||
fail("Unexpected invocation of visitCacheItems");
|
||||
|
@ -5502,7 +5503,6 @@ class TestAnalysisContext implements InternalAnalysisContext {
|
|||
fail("Unexpected invocation of getSourceFactory");
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
void set sourceFactory(SourceFactory factory) {
|
||||
fail("Unexpected invocation of setSourceFactory");
|
||||
|
@ -5750,6 +5750,7 @@ class TestAnalysisContext implements InternalAnalysisContext {
|
|||
void recordLibraryElements(Map<Source, LibraryElement> elementMap) {
|
||||
fail("Unexpected invocation of recordLibraryElements");
|
||||
}
|
||||
|
||||
@override
|
||||
void removeListener(AnalysisListener listener) {
|
||||
fail("Unexpected invocation of removeListener");
|
||||
|
|
|
@ -5,14 +5,19 @@
|
|||
library test.src.task.driver_test;
|
||||
|
||||
import 'package:analyzer/src/context/cache.dart';
|
||||
import 'package:analyzer/src/generated/ast.dart';
|
||||
import 'package:analyzer/src/generated/engine.dart'
|
||||
show AnalysisContext, CacheState, RetentionPriority;
|
||||
show
|
||||
AnalysisContext,
|
||||
CacheState,
|
||||
InternalAnalysisContext,
|
||||
RetentionPriority;
|
||||
import 'package:analyzer/src/generated/java_engine.dart';
|
||||
import 'package:analyzer/src/generated/sdk_io.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';
|
||||
import 'package:typed_mock/typed_mock.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
|
||||
import '../../generated/engine_test.dart';
|
||||
|
@ -23,6 +28,7 @@ main() {
|
|||
groupSep = ' | ';
|
||||
runReflectiveTests(AnalysisCacheTest);
|
||||
runReflectiveTests(CacheEntryTest);
|
||||
runReflectiveTests(CacheFlushManagerTest);
|
||||
runReflectiveTests(SdkCachePartitionTest);
|
||||
runReflectiveTests(UniversalCachePartitionTest);
|
||||
runReflectiveTests(ResultDataTest);
|
||||
|
@ -30,35 +36,12 @@ main() {
|
|||
|
||||
AnalysisCache createCache({AnalysisContext context,
|
||||
RetentionPriority policy: RetentionPriority.LOW}) {
|
||||
CachePartition partition = new UniversalCachePartition(
|
||||
context, 8, new TestCacheRetentionPolicy(policy));
|
||||
CachePartition partition = new UniversalCachePartition(context);
|
||||
return new AnalysisCache(<CachePartition>[partition]);
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class AnalysisCacheTest extends EngineTestCase {
|
||||
void test_astSize_empty() {
|
||||
AnalysisCache cache = createCache();
|
||||
expect(cache.astSize, 0);
|
||||
}
|
||||
|
||||
void test_astSize_nonEmpty() {
|
||||
ResultDescriptor result = new ResultDescriptor('test', null);
|
||||
AstNode node = new NullLiteral(null);
|
||||
AnalysisCache cache = createCache();
|
||||
AnalysisTarget target1 = new TestSource('/test1.dart');
|
||||
CacheEntry entry1 = new CacheEntry();
|
||||
entry1.setValue(result, node, TargetedResult.EMPTY_LIST, null);
|
||||
AnalysisTarget target2 = new TestSource('/test2.dart');
|
||||
CacheEntry entry2 = new CacheEntry();
|
||||
entry2.setValue(result, node, TargetedResult.EMPTY_LIST, null);
|
||||
cache.put(target1, entry1);
|
||||
cache.accessedAst(target1);
|
||||
cache.put(target2, entry2);
|
||||
cache.accessedAst(target2);
|
||||
expect(cache.astSize, 2);
|
||||
}
|
||||
|
||||
void test_creation() {
|
||||
expect(createCache(), isNotNull);
|
||||
}
|
||||
|
@ -103,38 +86,6 @@ class AnalysisCacheTest extends EngineTestCase {
|
|||
cache.remove(target);
|
||||
}
|
||||
|
||||
void test_setMaxCacheSize() {
|
||||
CachePartition partition = new UniversalCachePartition(
|
||||
null, 8, new TestCacheRetentionPolicy(RetentionPriority.MEDIUM));
|
||||
AnalysisCache cache = new AnalysisCache(<CachePartition>[partition]);
|
||||
ResultDescriptor result = new ResultDescriptor('test', null);
|
||||
AstNode node = new NullLiteral(null);
|
||||
int size = 6;
|
||||
for (int i = 0; i < size; i++) {
|
||||
AnalysisTarget target = new TestSource("/test$i.dart");
|
||||
CacheEntry entry = new CacheEntry();
|
||||
entry.setValue(result, node, TargetedResult.EMPTY_LIST, null);
|
||||
cache.put(target, entry);
|
||||
cache.accessedAst(target);
|
||||
}
|
||||
|
||||
void _assertNonFlushedCount(int expectedCount, AnalysisCache cache) {
|
||||
int nonFlushedCount = 0;
|
||||
MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
|
||||
while (iterator.moveNext()) {
|
||||
if (iterator.value.getState(result) != CacheState.FLUSHED) {
|
||||
nonFlushedCount++;
|
||||
}
|
||||
}
|
||||
expect(nonFlushedCount, expectedCount);
|
||||
}
|
||||
|
||||
_assertNonFlushedCount(size, cache);
|
||||
int newSize = size - 2;
|
||||
partition.maxCacheSize = newSize;
|
||||
_assertNonFlushedCount(newSize, cache);
|
||||
}
|
||||
|
||||
void test_size() {
|
||||
AnalysisCache cache = createCache();
|
||||
int size = 4;
|
||||
|
@ -148,6 +99,16 @@ class AnalysisCacheTest extends EngineTestCase {
|
|||
|
||||
@reflectiveTest
|
||||
class CacheEntryTest extends EngineTestCase {
|
||||
InternalAnalysisContext context;
|
||||
AnalysisCache cache;
|
||||
|
||||
void setUp() {
|
||||
context = new _InternalAnalysisContextMock();
|
||||
when(context.priorityTargets).thenReturn([]);
|
||||
cache = createCache(context: context);
|
||||
// when(context.analysisCache).thenReturn(cache);
|
||||
}
|
||||
|
||||
test_explicitlyAdded() {
|
||||
CacheEntry entry = new CacheEntry();
|
||||
expect(entry.explicitlyAdded, false);
|
||||
|
@ -186,14 +147,11 @@ class CacheEntryTest extends EngineTestCase {
|
|||
expect(entry.exception, isNull);
|
||||
}
|
||||
|
||||
test_flushAstStructures() {
|
||||
ResultDescriptor result = new ResultDescriptor('test', null);
|
||||
test_getMemento_noResult() {
|
||||
String defaultValue = 'value';
|
||||
ResultDescriptor result = new ResultDescriptor('test', defaultValue);
|
||||
CacheEntry entry = new CacheEntry();
|
||||
entry.setValue(
|
||||
result, new NullLiteral(null), TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.hasAstStructure, true);
|
||||
entry.flushAstStructures();
|
||||
expect(entry.hasAstStructure, false);
|
||||
expect(entry.getMemento(result), null);
|
||||
}
|
||||
|
||||
test_getState() {
|
||||
|
@ -209,24 +167,34 @@ class CacheEntryTest extends EngineTestCase {
|
|||
expect(entry.getValue(result), defaultValue);
|
||||
}
|
||||
|
||||
test_getMemento_noResult() {
|
||||
String defaultValue = 'value';
|
||||
ResultDescriptor result = new ResultDescriptor('test', defaultValue);
|
||||
test_getValue_flushResults() {
|
||||
ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
|
||||
ResultDescriptor descriptor1 =
|
||||
new ResultDescriptor('result1', null, cachingPolicy: cachingPolicy);
|
||||
ResultDescriptor descriptor2 =
|
||||
new ResultDescriptor('result2', null, cachingPolicy: cachingPolicy);
|
||||
ResultDescriptor descriptor3 =
|
||||
new ResultDescriptor('result3', null, cachingPolicy: cachingPolicy);
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
expect(entry.getMemento(result), null);
|
||||
}
|
||||
|
||||
test_hasAstStructure_false() {
|
||||
CacheEntry entry = new CacheEntry();
|
||||
expect(entry.hasAstStructure, false);
|
||||
}
|
||||
|
||||
test_hasAstStructure_true() {
|
||||
ResultDescriptor result = new ResultDescriptor('test', null);
|
||||
CacheEntry entry = new CacheEntry();
|
||||
entry.setValue(
|
||||
result, new NullLiteral(null), TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.hasAstStructure, true);
|
||||
cache.put(target, entry);
|
||||
{
|
||||
entry.setValue(descriptor1, 1, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.VALID);
|
||||
}
|
||||
{
|
||||
entry.setValue(descriptor2, 2, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.VALID);
|
||||
expect(entry.getState(descriptor2), CacheState.VALID);
|
||||
}
|
||||
// get descriptor1, so that descriptor2 will be flushed
|
||||
entry.getValue(descriptor1);
|
||||
{
|
||||
entry.setValue(descriptor3, 3, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.VALID);
|
||||
expect(entry.getState(descriptor2), CacheState.FLUSHED);
|
||||
expect(entry.getState(descriptor3), CacheState.VALID);
|
||||
}
|
||||
}
|
||||
|
||||
test_hasErrorState_false() {
|
||||
|
@ -274,7 +242,6 @@ class CacheEntryTest extends EngineTestCase {
|
|||
}
|
||||
|
||||
test_setErrorState_invalidateDependent() {
|
||||
AnalysisCache cache = createCache();
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
cache.put(target, entry);
|
||||
|
@ -388,7 +355,6 @@ class CacheEntryTest extends EngineTestCase {
|
|||
}
|
||||
|
||||
test_setState_invalid_invalidateDependent() {
|
||||
AnalysisCache cache = createCache();
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
cache.put(target, entry);
|
||||
|
@ -438,8 +404,35 @@ class CacheEntryTest extends EngineTestCase {
|
|||
expect(entry.getMemento(result), memento);
|
||||
}
|
||||
|
||||
test_setValue_flushResults() {
|
||||
ResultCachingPolicy cachingPolicy = new SimpleResultCachingPolicy(2, 2);
|
||||
ResultDescriptor descriptor1 =
|
||||
new ResultDescriptor('result1', null, cachingPolicy: cachingPolicy);
|
||||
ResultDescriptor descriptor2 =
|
||||
new ResultDescriptor('result2', null, cachingPolicy: cachingPolicy);
|
||||
ResultDescriptor descriptor3 =
|
||||
new ResultDescriptor('result3', null, cachingPolicy: cachingPolicy);
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
cache.put(target, entry);
|
||||
{
|
||||
entry.setValue(descriptor1, 1, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.VALID);
|
||||
}
|
||||
{
|
||||
entry.setValue(descriptor2, 2, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.VALID);
|
||||
expect(entry.getState(descriptor2), CacheState.VALID);
|
||||
}
|
||||
{
|
||||
entry.setValue(descriptor3, 3, TargetedResult.EMPTY_LIST, null);
|
||||
expect(entry.getState(descriptor1), CacheState.FLUSHED);
|
||||
expect(entry.getState(descriptor2), CacheState.VALID);
|
||||
expect(entry.getState(descriptor3), CacheState.VALID);
|
||||
}
|
||||
}
|
||||
|
||||
test_setValue_invalidateDependent() {
|
||||
AnalysisCache cache = createCache();
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
cache.put(target, entry);
|
||||
|
@ -473,7 +466,6 @@ class CacheEntryTest extends EngineTestCase {
|
|||
}
|
||||
|
||||
test_setValue_invalidateDependent2() {
|
||||
AnalysisCache cache = createCache();
|
||||
AnalysisTarget target1 = new TestSource('a');
|
||||
AnalysisTarget target2 = new TestSource('b');
|
||||
CacheEntry entry1 = new CacheEntry();
|
||||
|
@ -517,8 +509,149 @@ class CacheEntryTest extends EngineTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class CacheFlushManagerTest {
|
||||
CacheFlushManager manager = new CacheFlushManager(
|
||||
new SimpleResultCachingPolicy(15, 3), (AnalysisTarget target) => false);
|
||||
|
||||
test_madeActive() {
|
||||
manager.madeActive();
|
||||
expect(manager.maxSize, 15);
|
||||
}
|
||||
|
||||
test_madeIdle() {
|
||||
manager.madeActive();
|
||||
AnalysisTarget target = new TestSource();
|
||||
// prepare TargetedResult(s)
|
||||
List<TargetedResult> results = <TargetedResult>[];
|
||||
for (int i = 0; i < 15; i++) {
|
||||
ResultDescriptor descriptor = new ResultDescriptor('result$i', null);
|
||||
results.add(new TargetedResult(target, descriptor));
|
||||
}
|
||||
// notify about storing TargetedResult(s)
|
||||
for (TargetedResult result in results) {
|
||||
manager.resultStored(result, null);
|
||||
}
|
||||
expect(manager.recentlyUsed, results);
|
||||
expect(manager.currentSize, 15);
|
||||
// make idle
|
||||
List<TargetedResult> resultsToFlush = manager.madeIdle();
|
||||
expect(manager.maxSize, 3);
|
||||
expect(manager.recentlyUsed, results.skip(15 - 3));
|
||||
expect(resultsToFlush, results.take(15 - 3));
|
||||
}
|
||||
|
||||
test_new() {
|
||||
expect(manager.maxActiveSize, 15);
|
||||
expect(manager.maxIdleSize, 3);
|
||||
expect(manager.maxSize, 3);
|
||||
expect(manager.currentSize, 0);
|
||||
expect(manager.recentlyUsed, isEmpty);
|
||||
}
|
||||
|
||||
test_resultAccessed() {
|
||||
ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
|
||||
ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
|
||||
ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
|
||||
AnalysisTarget target = new TestSource();
|
||||
TargetedResult result1 = new TargetedResult(target, descriptor1);
|
||||
TargetedResult result2 = new TargetedResult(target, descriptor2);
|
||||
TargetedResult result3 = new TargetedResult(target, descriptor3);
|
||||
manager.resultStored(result1, null);
|
||||
manager.resultStored(result2, null);
|
||||
manager.resultStored(result3, null);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
|
||||
// access result2
|
||||
manager.resultAccessed(result2);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
|
||||
}
|
||||
|
||||
test_resultAccessed_noSuchResult() {
|
||||
ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
|
||||
ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
|
||||
ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
|
||||
AnalysisTarget target = new TestSource();
|
||||
TargetedResult result1 = new TargetedResult(target, descriptor1);
|
||||
TargetedResult result2 = new TargetedResult(target, descriptor2);
|
||||
TargetedResult result3 = new TargetedResult(target, descriptor3);
|
||||
manager.resultStored(result1, null);
|
||||
manager.resultStored(result2, null);
|
||||
expect(manager.currentSize, 2);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result2]));
|
||||
// access result3, no-op
|
||||
manager.resultAccessed(result3);
|
||||
expect(manager.currentSize, 2);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result2]));
|
||||
}
|
||||
|
||||
test_resultStored() {
|
||||
ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
|
||||
ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
|
||||
ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
|
||||
ResultDescriptor descriptor4 = new ResultDescriptor('result4', null);
|
||||
AnalysisTarget target = new TestSource();
|
||||
TargetedResult result1 = new TargetedResult(target, descriptor1);
|
||||
TargetedResult result2 = new TargetedResult(target, descriptor2);
|
||||
TargetedResult result3 = new TargetedResult(target, descriptor3);
|
||||
TargetedResult result4 = new TargetedResult(target, descriptor4);
|
||||
manager.resultStored(result1, null);
|
||||
manager.resultStored(result2, null);
|
||||
manager.resultStored(result3, null);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
|
||||
// store result2 again
|
||||
{
|
||||
List<TargetedResult> resultsToFlush = manager.resultStored(result2, null);
|
||||
expect(resultsToFlush, isEmpty);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result3, result2]));
|
||||
}
|
||||
// store result4
|
||||
{
|
||||
List<TargetedResult> resultsToFlush = manager.resultStored(result4, null);
|
||||
expect(resultsToFlush, [result1]);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result3, result2, result4]));
|
||||
expect(manager.resultSizeMap, {result3: 1, result2: 1, result4: 1});
|
||||
}
|
||||
}
|
||||
|
||||
test_targetRemoved() {
|
||||
ResultDescriptor descriptor1 = new ResultDescriptor('result1', null);
|
||||
ResultDescriptor descriptor2 = new ResultDescriptor('result2', null);
|
||||
ResultDescriptor descriptor3 = new ResultDescriptor('result3', null);
|
||||
AnalysisTarget target1 = new TestSource('a.dart');
|
||||
AnalysisTarget target2 = new TestSource('b.dart');
|
||||
TargetedResult result1 = new TargetedResult(target1, descriptor1);
|
||||
TargetedResult result2 = new TargetedResult(target2, descriptor2);
|
||||
TargetedResult result3 = new TargetedResult(target1, descriptor3);
|
||||
manager.resultStored(result1, null);
|
||||
manager.resultStored(result2, null);
|
||||
manager.resultStored(result3, null);
|
||||
expect(manager.currentSize, 3);
|
||||
expect(manager.recentlyUsed, orderedEquals([result1, result2, result3]));
|
||||
expect(manager.resultSizeMap, {result1: 1, result2: 1, result3: 1});
|
||||
// remove target1
|
||||
{
|
||||
manager.targetRemoved(target1);
|
||||
expect(manager.currentSize, 1);
|
||||
expect(manager.recentlyUsed, orderedEquals([result2]));
|
||||
expect(manager.resultSizeMap, {result2: 1});
|
||||
}
|
||||
// remove target2
|
||||
{
|
||||
manager.targetRemoved(target2);
|
||||
expect(manager.currentSize, 0);
|
||||
expect(manager.recentlyUsed, isEmpty);
|
||||
expect(manager.resultSizeMap, isEmpty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class CachePartitionTest extends EngineTestCase {
|
||||
CachePartition createPartition([CacheRetentionPolicy policy = null]);
|
||||
CachePartition createPartition();
|
||||
|
||||
void test_creation() {
|
||||
expect(createPartition(), isNotNull);
|
||||
|
@ -542,6 +675,15 @@ abstract class CachePartitionTest extends EngineTestCase {
|
|||
expect(partition.get(target), isNull);
|
||||
}
|
||||
|
||||
void test_put_alreadyInPartition() {
|
||||
CachePartition partition1 = createPartition();
|
||||
CachePartition partition2 = createPartition();
|
||||
AnalysisTarget target = new TestSource();
|
||||
CacheEntry entry = new CacheEntry();
|
||||
partition1.put(target, entry);
|
||||
expect(() => partition2.put(target, entry), throwsStateError);
|
||||
}
|
||||
|
||||
void test_put_noFlush() {
|
||||
CachePartition partition = createPartition();
|
||||
AnalysisTarget target = new TestSource();
|
||||
|
@ -559,48 +701,6 @@ abstract class CachePartitionTest extends EngineTestCase {
|
|||
partition.remove(target);
|
||||
expect(partition.get(target), isNull);
|
||||
}
|
||||
|
||||
void test_setMaxCacheSize() {
|
||||
CachePartition partition =
|
||||
createPartition(new TestCacheRetentionPolicy(RetentionPriority.LOW));
|
||||
ResultDescriptor result = new ResultDescriptor('result', null);
|
||||
NullLiteral node = new NullLiteral(null);
|
||||
int size = 6; // Must be <= partition.maxCacheSize
|
||||
for (int i = 0; i < size; i++) {
|
||||
AnalysisTarget target = new TestSource("/test$i.dart");
|
||||
CacheEntry entry = new CacheEntry();
|
||||
entry.setValue(result, node, TargetedResult.EMPTY_LIST, null);
|
||||
partition.put(target, entry);
|
||||
partition.accessedAst(target);
|
||||
}
|
||||
|
||||
void assertNonFlushedCount(int expectedCount, CachePartition partition) {
|
||||
int nonFlushedCount = 0;
|
||||
Map<AnalysisTarget, CacheEntry> entryMap = partition.map;
|
||||
entryMap.values.forEach((CacheEntry entry) {
|
||||
if (entry.getState(result) != CacheState.FLUSHED) {
|
||||
nonFlushedCount++;
|
||||
}
|
||||
});
|
||||
expect(nonFlushedCount, expectedCount);
|
||||
}
|
||||
|
||||
assertNonFlushedCount(size, partition);
|
||||
int newSize = size - 2;
|
||||
partition.maxCacheSize = newSize;
|
||||
assertNonFlushedCount(newSize, partition);
|
||||
}
|
||||
|
||||
void test_size() {
|
||||
CachePartition partition = createPartition();
|
||||
int size = 4;
|
||||
for (int i = 0; i < size; i++) {
|
||||
AnalysisTarget target = new TestSource("/test$i.dart");
|
||||
partition.put(target, new CacheEntry());
|
||||
partition.accessedAst(target);
|
||||
}
|
||||
expect(partition.size(), size);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
|
@ -616,8 +716,8 @@ class ResultDataTest extends EngineTestCase {
|
|||
|
||||
@reflectiveTest
|
||||
class SdkCachePartitionTest extends CachePartitionTest {
|
||||
CachePartition createPartition([CacheRetentionPolicy policy = null]) {
|
||||
return new SdkCachePartition(null, 8);
|
||||
CachePartition createPartition() {
|
||||
return new SdkCachePartition(null);
|
||||
}
|
||||
|
||||
void test_contains_false() {
|
||||
|
@ -627,7 +727,7 @@ class SdkCachePartitionTest extends CachePartitionTest {
|
|||
}
|
||||
|
||||
void test_contains_true() {
|
||||
SdkCachePartition partition = new SdkCachePartition(null, 8);
|
||||
SdkCachePartition partition = new SdkCachePartition(null);
|
||||
SourceFactory factory = new SourceFactory(
|
||||
[new DartUriResolver(DirectoryBasedDartSdk.defaultSdk)]);
|
||||
AnalysisTarget target = factory.forUri("dart:core");
|
||||
|
@ -635,27 +735,20 @@ class SdkCachePartitionTest extends CachePartitionTest {
|
|||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class TestCacheRetentionPolicy extends CacheRetentionPolicy {
|
||||
final RetentionPriority policy;
|
||||
|
||||
TestCacheRetentionPolicy([this.policy = RetentionPriority.MEDIUM]);
|
||||
|
||||
@override
|
||||
RetentionPriority getAstPriority(AnalysisTarget target, CacheEntry entry) =>
|
||||
policy;
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class UniversalCachePartitionTest extends CachePartitionTest {
|
||||
CachePartition createPartition([CacheRetentionPolicy policy = null]) {
|
||||
return new UniversalCachePartition(null, 8, policy);
|
||||
CachePartition createPartition() {
|
||||
return new UniversalCachePartition(null);
|
||||
}
|
||||
|
||||
void test_contains() {
|
||||
UniversalCachePartition partition =
|
||||
new UniversalCachePartition(null, 8, null);
|
||||
UniversalCachePartition partition = new UniversalCachePartition(null);
|
||||
TestSource source = new TestSource();
|
||||
expect(partition.contains(source), isTrue);
|
||||
}
|
||||
}
|
||||
|
||||
class _InternalAnalysisContextMock extends TypedMock
|
||||
implements InternalAnalysisContext {
|
||||
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import 'package:analyzer/src/generated/engine.dart'
|
|||
AnalysisOptions,
|
||||
AnalysisOptionsImpl,
|
||||
AnalysisResult,
|
||||
CacheState,
|
||||
ChangeNotice,
|
||||
ChangeSet,
|
||||
IncrementalAnalysisCache,
|
||||
|
@ -38,6 +39,7 @@ import 'package:analyzer/src/generated/sdk_io.dart';
|
|||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/generated/source_io.dart';
|
||||
import 'package:analyzer/src/plugin/engine_plugin.dart';
|
||||
import 'package:analyzer/task/dart.dart';
|
||||
import 'package:plugin/manager.dart';
|
||||
import 'package:unittest/unittest.dart';
|
||||
import 'package:watcher/src/utils.dart';
|
||||
|
@ -282,11 +284,6 @@ import 'libB.dart';''';
|
|||
expect(_context.computeImportedLibraries(source), hasLength(2));
|
||||
}
|
||||
|
||||
void test_computeKindOf_html() {
|
||||
Source source = _addSource("/test.html", "");
|
||||
expect(_context.computeKindOf(source), same(SourceKind.HTML));
|
||||
}
|
||||
|
||||
void fail_computeResolvableCompilationUnit_dart_exception() {
|
||||
TestSource source = _addSourceWithException("/test.dart");
|
||||
try {
|
||||
|
@ -324,8 +321,7 @@ import 'libB.dart';''';
|
|||
// Complete all pending analysis tasks and flush the AST so that it won't
|
||||
// be available immediately.
|
||||
_performPendingAnalysisTasks();
|
||||
CacheEntry entry = _context.getReadableSourceEntryOrNull(source);
|
||||
entry.flushAstStructures();
|
||||
_flushAst(source);
|
||||
CancelableFuture<CompilationUnit> future =
|
||||
_context.computeResolvedCompilationUnitAsync(source, source);
|
||||
bool completed = false;
|
||||
|
@ -512,27 +508,6 @@ class A {
|
|||
expect(sources[0], source);
|
||||
}
|
||||
|
||||
void test_getKindOf_html() {
|
||||
Source source = _addSource("/test.html", "");
|
||||
expect(_context.getKindOf(source), same(SourceKind.HTML));
|
||||
}
|
||||
|
||||
void test_getLibrariesContaining() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
Source librarySource = _addSource("/lib.dart", r'''
|
||||
library lib;
|
||||
part 'part.dart';''');
|
||||
Source partSource = _addSource("/part.dart", "part of lib;");
|
||||
_context.computeLibraryElement(librarySource);
|
||||
List<Source> result = _context.getLibrariesContaining(librarySource);
|
||||
expect(result, hasLength(1));
|
||||
expect(result[0], librarySource);
|
||||
result = _context.getLibrariesContaining(partSource);
|
||||
expect(result, hasLength(1));
|
||||
expect(result[0], librarySource);
|
||||
}
|
||||
|
||||
void fail_getLibrariesReferencedFromHtml() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
|
@ -1117,6 +1092,19 @@ library test2;''');
|
|||
_context.analysisOptions = options;
|
||||
}
|
||||
|
||||
void test_applyChanges_change_flush_element() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
Source librarySource = _addSource("/lib.dart", r'''
|
||||
library lib;
|
||||
int a = 0;''');
|
||||
expect(_context.computeLibraryElement(librarySource), isNotNull);
|
||||
_context.setContents(librarySource, r'''
|
||||
library lib;
|
||||
int aa = 0;''');
|
||||
expect(_context.getLibraryElement(librarySource), isNull);
|
||||
}
|
||||
|
||||
@override
|
||||
void tearDown() {
|
||||
_context = null;
|
||||
|
@ -1186,19 +1174,6 @@ library test2;''');
|
|||
});
|
||||
}
|
||||
|
||||
void test_applyChanges_change_flush_element() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
Source librarySource = _addSource("/lib.dart", r'''
|
||||
library lib;
|
||||
int a = 0;''');
|
||||
expect(_context.computeLibraryElement(librarySource), isNotNull);
|
||||
_context.setContents(librarySource, r'''
|
||||
library lib;
|
||||
int aa = 0;''');
|
||||
expect(_context.getLibraryElement(librarySource), isNull);
|
||||
}
|
||||
|
||||
Future test_applyChanges_change_multiple() {
|
||||
_context = contextWithCore();
|
||||
SourcesChangedListener listener = new SourcesChangedListener();
|
||||
|
@ -1346,6 +1321,11 @@ class A {}""");
|
|||
expect(_context.computeHtmlElement(source), isNull);
|
||||
}
|
||||
|
||||
void test_computeKindOf_html() {
|
||||
Source source = _addSource("/test.html", "");
|
||||
expect(_context.computeKindOf(source), same(SourceKind.HTML));
|
||||
}
|
||||
|
||||
void test_computeKindOf_library() {
|
||||
Source source = _addSource("/test.dart", "library lib;");
|
||||
expect(_context.computeKindOf(source), same(SourceKind.LIBRARY));
|
||||
|
@ -1396,8 +1376,7 @@ main() {}''');
|
|||
// Complete all pending analysis tasks and flush the AST so that it won't
|
||||
// be available immediately.
|
||||
_performPendingAnalysisTasks();
|
||||
CacheEntry entry = _context.getReadableSourceEntryOrNull(source);
|
||||
entry.flushAstStructures();
|
||||
_flushAst(source);
|
||||
// Dispose of the context.
|
||||
_context.dispose();
|
||||
// Any attempt to start an asynchronous computation should return a future
|
||||
|
@ -1515,6 +1494,11 @@ main() {}''');
|
|||
expect(result, hasLength(0));
|
||||
}
|
||||
|
||||
void test_getKindOf_html() {
|
||||
Source source = _addSource("/test.html", "");
|
||||
expect(_context.getKindOf(source), same(SourceKind.HTML));
|
||||
}
|
||||
|
||||
void test_getKindOf_library() {
|
||||
Source source = _addSource("/test.dart", "library lib;");
|
||||
expect(_context.getKindOf(source), same(SourceKind.UNKNOWN));
|
||||
|
@ -1630,6 +1614,22 @@ main() {}''');
|
|||
expect(_context.launchableServerLibrarySources, isEmpty);
|
||||
}
|
||||
|
||||
void test_getLibrariesContaining() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
Source librarySource = _addSource("/lib.dart", r'''
|
||||
library lib;
|
||||
part 'part.dart';''');
|
||||
Source partSource = _addSource("/part.dart", "part of lib;");
|
||||
_context.computeLibraryElement(librarySource);
|
||||
List<Source> result = _context.getLibrariesContaining(librarySource);
|
||||
expect(result, hasLength(1));
|
||||
expect(result[0], librarySource);
|
||||
result = _context.getLibrariesContaining(partSource);
|
||||
expect(result, hasLength(1));
|
||||
expect(result[0], librarySource);
|
||||
}
|
||||
|
||||
void test_getLibrariesDependingOn() {
|
||||
_context = contextWithCore();
|
||||
_sourceFactory = _context.sourceFactory;
|
||||
|
@ -1860,17 +1860,6 @@ main() {}''');
|
|||
expect(errorInfo.errors, hasLength(0));
|
||||
}
|
||||
|
||||
// void test_resolveCompilationUnit_sourceChangeDuringResolution() {
|
||||
// _context = new _AnalysisContext_sourceChangeDuringResolution();
|
||||
// AnalysisContextFactory.initContextWithCore(_context);
|
||||
// _sourceFactory = _context.sourceFactory;
|
||||
// Source source = _addSource("/lib.dart", "library lib;");
|
||||
// CompilationUnit compilationUnit =
|
||||
// _context.resolveCompilationUnit2(source, source);
|
||||
// expect(compilationUnit, isNotNull);
|
||||
// expect(_context.getLineInfo(source), isNotNull);
|
||||
// }
|
||||
|
||||
void test_parseCompilationUnit_nonExistentSource() {
|
||||
Source source =
|
||||
new FileBasedSource.con1(FileUtilities2.createFile("/test.dart"));
|
||||
|
@ -1882,6 +1871,17 @@ main() {}''');
|
|||
}
|
||||
}
|
||||
|
||||
// void test_resolveCompilationUnit_sourceChangeDuringResolution() {
|
||||
// _context = new _AnalysisContext_sourceChangeDuringResolution();
|
||||
// AnalysisContextFactory.initContextWithCore(_context);
|
||||
// _sourceFactory = _context.sourceFactory;
|
||||
// Source source = _addSource("/lib.dart", "library lib;");
|
||||
// CompilationUnit compilationUnit =
|
||||
// _context.resolveCompilationUnit2(source, source);
|
||||
// expect(compilationUnit, isNotNull);
|
||||
// expect(_context.getLineInfo(source), isNotNull);
|
||||
// }
|
||||
|
||||
void test_performAnalysisTask_modifiedAfterParse() {
|
||||
// TODO(scheglov) no threads in Dart
|
||||
// Source source = _addSource("/test.dart", "library lib;");
|
||||
|
@ -2044,8 +2044,7 @@ int a = 0;''');
|
|||
// Complete all pending analysis tasks and flush the AST so that it won't
|
||||
// be available immediately.
|
||||
_performPendingAnalysisTasks();
|
||||
CacheEntry entry = _context.getReadableSourceEntryOrNull(source);
|
||||
entry.flushAstStructures();
|
||||
_flushAst(source);
|
||||
bool completed = false;
|
||||
_context
|
||||
.computeResolvedCompilationUnitAsync(source, source)
|
||||
|
@ -2068,8 +2067,7 @@ int a = 0;''');
|
|||
// Complete all pending analysis tasks and flush the AST so that it won't
|
||||
// be available immediately.
|
||||
_performPendingAnalysisTasks();
|
||||
CacheEntry entry = _context.getReadableSourceEntryOrNull(source);
|
||||
entry.flushAstStructures();
|
||||
_flushAst(source);
|
||||
CancelableFuture<CompilationUnit> future =
|
||||
_context.computeResolvedCompilationUnitAsync(source, source);
|
||||
bool completed = false;
|
||||
|
@ -2188,6 +2186,11 @@ int a = 0;''');
|
|||
return null;
|
||||
}
|
||||
|
||||
void _flushAst(Source source) {
|
||||
CacheEntry entry = _context.getReadableSourceEntryOrNull(source);
|
||||
entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
|
||||
}
|
||||
|
||||
IncrementalAnalysisCache _getIncrementalAnalysisCache(
|
||||
AnalysisContextImpl context2) {
|
||||
return context2.test_incrementalAnalysisCache;
|
||||
|
|
|
@ -19,6 +19,7 @@ main() {
|
|||
runReflectiveTests(AnalysisTaskTest);
|
||||
runReflectiveTests(ContributionPointImplTest);
|
||||
runReflectiveTests(ResultDescriptorImplTest);
|
||||
runReflectiveTests(SimpleResultCachingPolicyTest);
|
||||
runReflectiveTests(TaskDescriptorImplTest);
|
||||
}
|
||||
|
||||
|
@ -94,6 +95,13 @@ class ContributionPointImplTest extends EngineTestCase {
|
|||
|
||||
@reflectiveTest
|
||||
class ResultDescriptorImplTest extends EngineTestCase {
|
||||
test_create_withCachingPolicy() {
|
||||
ResultCachingPolicy policy = new SimpleResultCachingPolicy(128, 16);
|
||||
ResultDescriptorImpl result =
|
||||
new ResultDescriptorImpl('result', null, cachingPolicy: policy);
|
||||
expect(result.cachingPolicy, same(policy));
|
||||
}
|
||||
|
||||
test_create_withContribution() {
|
||||
CompositeResultDescriptorImpl point =
|
||||
new CompositeResultDescriptorImpl('point');
|
||||
|
@ -104,6 +112,14 @@ class ResultDescriptorImplTest extends EngineTestCase {
|
|||
expect(contributors, unorderedEquals([result]));
|
||||
}
|
||||
|
||||
test_create_withoutCachingPolicy() {
|
||||
ResultDescriptorImpl result = new ResultDescriptorImpl('result', null);
|
||||
ResultCachingPolicy cachingPolicy = result.cachingPolicy;
|
||||
expect(cachingPolicy, isNotNull);
|
||||
expect(cachingPolicy.maxActiveSize, -1);
|
||||
expect(cachingPolicy.maxIdleSize, -1);
|
||||
}
|
||||
|
||||
test_create_withoutContribution() {
|
||||
expect(new ResultDescriptorImpl('name', null), isNotNull);
|
||||
}
|
||||
|
@ -122,6 +138,16 @@ class ResultDescriptorImplTest extends EngineTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class SimpleResultCachingPolicyTest extends EngineTestCase {
|
||||
test_create() {
|
||||
ResultCachingPolicy policy = new SimpleResultCachingPolicy(256, 32);
|
||||
expect(policy.maxActiveSize, 256);
|
||||
expect(policy.maxIdleSize, 32);
|
||||
expect(policy.measure(null), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class TaskDescriptorImplTest extends EngineTestCase {
|
||||
test_create() {
|
||||
|
|
Loading…
Reference in a new issue