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

Side by Side Diff: packages/analyzer/lib/src/context/cache.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.context.cache; 5 library analyzer.src.context.cache;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 import 'package:analyzer/src/generated/engine.dart' 10 import 'package:analyzer/exception/exception.dart';
11 show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority; 11 import 'package:analyzer/file_system/file_system.dart';
12 import 'package:analyzer/src/generated/java_engine.dart'; 12 import 'package:analyzer/src/generated/engine.dart';
13 import 'package:analyzer/src/generated/source.dart'; 13 import 'package:analyzer/src/generated/source.dart';
14 import 'package:analyzer/src/generated/utilities_collection.dart'; 14 import 'package:analyzer/src/generated/utilities_collection.dart';
15 import 'package:analyzer/src/task/model.dart'; 15 import 'package:analyzer/src/task/model.dart';
16 import 'package:analyzer/task/model.dart'; 16 import 'package:analyzer/task/model.dart';
17 17
18 /** 18 /**
19 * The cache results visiting function type.
20 */
21 typedef void CacheResultVisitor(AnalysisTarget target, ResultData data);
22
23 /**
24 * Return `true` if the [result] of the [target] should be flushed.
25 */
26 typedef bool FlushResultFilter<V>(
27 AnalysisTarget target, ResultDescriptor<V> result);
28
29 /**
19 * Return `true` if the given [target] is a priority one. 30 * Return `true` if the given [target] is a priority one.
20 */ 31 */
21 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target); 32 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target);
22 33
23 /** 34 /**
24 * An LRU cache of results produced by analysis. 35 * An LRU cache of results produced by analysis.
25 */ 36 */
26 class AnalysisCache { 37 class AnalysisCache {
27 /** 38 /**
28 * A flag used to control whether trace information should be produced when 39 * A flag used to control whether trace information should be produced when
29 * the content of the cache is modified. 40 * the content of the cache is modified.
30 */ 41 */
31 static bool _TRACE_CHANGES = false; 42 static bool _TRACE_CHANGES = false;
32 43
33 /** 44 /**
34 * An array containing the partitions of which this cache is comprised. 45 * An array containing the partitions of which this cache is comprised.
35 */ 46 */
36 final List<CachePartition> _partitions; 47 final List<CachePartition> _partitions;
37 48
38 /** 49 /**
39 * The [StreamController] reporting [InvalidatedResult]s. 50 * The [StreamController] reporting [InvalidatedResult]s.
40 */ 51 */
41 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated = 52 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
42 new ReentrantSynchronousStream<InvalidatedResult>(); 53 new ReentrantSynchronousStream<InvalidatedResult>();
43 54
55 final List<ReentrantSynchronousStreamSubscription>
56 onResultInvalidatedPartitionSubscriptions =
57 <ReentrantSynchronousStreamSubscription>[];
58
44 /** 59 /**
45 * Initialize a newly created cache to have the given [partitions]. The 60 * Initialize a newly created cache to have the given [_partitions]. The
46 * partitions will be searched in the order in which they appear in the array, 61 * partitions will be searched in the order in which they appear in the array,
47 * so the most specific partition (usually an [SdkCachePartition]) should be 62 * so the most specific partition (usually an [SdkCachePartition]) should be
48 * first and the most general (usually a [UniversalCachePartition]) last. 63 * first and the most general (usually a [UniversalCachePartition]) last.
49 */ 64 */
50 AnalysisCache(this._partitions) { 65 AnalysisCache(this._partitions) {
51 for (CachePartition partition in _partitions) { 66 for (CachePartition partition in _partitions) {
52 partition.onResultInvalidated.listen((InvalidatedResult event) { 67 partition.containingCaches.add(this);
68 ReentrantSynchronousStreamSubscription<InvalidatedResult> subscription =
69 partition.onResultInvalidated.listen((InvalidatedResult event) {
53 onResultInvalidated.add(event); 70 onResultInvalidated.add(event);
54 }); 71 });
72 onResultInvalidatedPartitionSubscriptions.add(subscription);
55 } 73 }
56 } 74 }
57 75
76 /**
77 * Return an iterator returning all of the [Source] targets.
78 */
79 Iterable<Source> get sources {
80 return _partitions
81 .map((CachePartition partition) => partition.sources)
82 .expand((Iterable<Source> sources) => sources);
83 }
84
58 // TODO(brianwilkerson) Implement or delete this. 85 // TODO(brianwilkerson) Implement or delete this.
59 // /** 86 // /**
60 // * Return information about each of the partitions in this cache. 87 // * Return information about each of the partitions in this cache.
61 // */ 88 // */
62 // List<AnalysisContextStatistics_PartitionData> get partitionData { 89 // List<AnalysisContextStatistics_PartitionData> get partitionData {
63 // int count = _partitions.length; 90 // int count = _partitions.length;
64 // List<AnalysisContextStatistics_PartitionData> data = 91 // List<AnalysisContextStatistics_PartitionData> data =
65 // new List<AnalysisContextStatistics_PartitionData>(count); 92 // new List<AnalysisContextStatistics_PartitionData>(count);
66 // for (int i = 0; i < count; i++) { 93 // for (int i = 0; i < count; i++) {
67 // CachePartition partition = _partitions[i]; 94 // CachePartition partition = _partitions[i];
68 // data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl( 95 // data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl(
69 // partition.astSize, 96 // partition.astSize,
70 // partition.map.length); 97 // partition.map.length);
71 // } 98 // }
72 // return data; 99 // return data;
73 // } 100 // }
74 101
75 /** 102 /**
76 * Return an iterator returning all of the [Source] targets. 103 * Free any allocated resources and references.
77 */ 104 */
78 Iterable<Source> get sources { 105 void dispose() {
79 return _partitions 106 for (ReentrantSynchronousStreamSubscription subscription
80 .map((CachePartition partition) => partition._sources) 107 in onResultInvalidatedPartitionSubscriptions) {
81 .expand((Iterable<Source> sources) => sources); 108 subscription.cancel();
109 }
110 for (CachePartition partition in _partitions) {
111 partition.containingCaches.remove(this);
112 }
82 } 113 }
83 114
84 /** 115 /**
116 * Flush results that satisfy the given [filter].
117 */
118 void flush(FlushResultFilter filter) {
119 for (CachePartition partition in _partitions) {
120 partition.flush(filter);
121 }
122 }
123
124 /**
85 * Return the entry associated with the given [target]. 125 * Return the entry associated with the given [target].
86 */ 126 */
87 CacheEntry get(AnalysisTarget target) { 127 CacheEntry get(AnalysisTarget target) {
88 int count = _partitions.length; 128 int count = _partitions.length;
89 for (int i = 0; i < count; i++) { 129 for (int i = 0; i < count; i++) {
90 CachePartition partition = _partitions[i]; 130 CachePartition partition = _partitions[i];
91 if (partition.isResponsibleFor(target)) { 131 if (partition.isResponsibleFor(target)) {
92 return partition.get(target); 132 return partition.get(target);
93 } 133 }
94 } 134 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 } 189 }
150 return entry.getState(result); 190 return entry.getState(result);
151 } 191 }
152 192
153 /** 193 /**
154 * Return the value of the given [result] for the given [target]. 194 * Return the value of the given [result] for the given [target].
155 * 195 *
156 * It does not update the cache, if the corresponding [CacheEntry] does not 196 * It does not update the cache, if the corresponding [CacheEntry] does not
157 * exist, then the default value is returned. 197 * exist, then the default value is returned.
158 */ 198 */
159 Object getValue(AnalysisTarget target, ResultDescriptor result) { 199 Object/*=V*/ getValue/*<V>*/(
200 AnalysisTarget target, ResultDescriptor/*<V>*/ result) {
160 CacheEntry entry = get(target); 201 CacheEntry entry = get(target);
161 if (entry == null) { 202 if (entry == null) {
162 return result.defaultValue; 203 return result.defaultValue;
163 } 204 }
164 return entry.getValue(result); 205 return entry.getValue(result);
165 } 206 }
166 207
167 /** 208 /**
168 * Return an iterator returning all of the map entries mapping targets to 209 * Return an iterator returning all of the map entries mapping targets to
169 * cache entries. If the [context] is not `null`, then only entries that are 210 * cache entries. If the [context] is not `null`, then only entries that are
170 * owned by the given context will be returned. 211 * owned by the given context will be returned.
171 */ 212 */
172 MapIterator<AnalysisTarget, CacheEntry> iterator( 213 MapIterator<AnalysisTarget, CacheEntry> iterator(
173 {InternalAnalysisContext context: null}) { 214 {InternalAnalysisContext context: null}) {
174 List<Map<AnalysisTarget, CacheEntry>> maps = 215 List<Map<AnalysisTarget, CacheEntry>> maps =
175 <Map<AnalysisTarget, CacheEntry>>[]; 216 <Map<AnalysisTarget, CacheEntry>>[];
176 for (CachePartition partition in _partitions) { 217 for (CachePartition partition in _partitions) {
177 if (context == null || partition.context == context) { 218 if (context == null || partition.context == context) {
178 maps.add(partition.map); 219 maps.add(partition.entryMap);
179 } 220 }
180 } 221 }
181 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); 222 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
182 } 223 }
183 224
184 /** 225 /**
185 * Puts the given [entry] into the cache. 226 * Puts the given [entry] into the cache.
186 */ 227 */
187 void put(CacheEntry entry) { 228 void put(CacheEntry entry) {
188 AnalysisTarget target = entry.target; 229 AnalysisTarget target = entry.target;
(...skipping 28 matching lines...) Expand all
217 */ 258 */
218 CacheEntry remove(AnalysisTarget target) { 259 CacheEntry remove(AnalysisTarget target) {
219 int count = _partitions.length; 260 int count = _partitions.length;
220 for (int i = 0; i < count; i++) { 261 for (int i = 0; i < count; i++) {
221 CachePartition partition = _partitions[i]; 262 CachePartition partition = _partitions[i];
222 if (partition.isResponsibleFor(target)) { 263 if (partition.isResponsibleFor(target)) {
223 if (_TRACE_CHANGES) { 264 if (_TRACE_CHANGES) {
224 AnalysisEngine.instance.logger 265 AnalysisEngine.instance.logger
225 .logInformation('Removed the cache entry for $target.'); 266 .logInformation('Removed the cache entry for $target.');
226 } 267 }
227 return partition.remove(target); 268 CacheEntry entry = partition.remove(target);
269 if (entry != null) {
270 entry.dispose();
271 }
272 return entry;
228 } 273 }
229 } 274 }
230 return null; 275 return null;
231 } 276 }
232 277
233 /** 278 /**
234 * Return the number of targets that are mapped to cache entries. 279 * Return the number of targets that are mapped to cache entries.
235 */ 280 */
236 int size() { 281 int size() {
237 int size = 0; 282 int size = 0;
(...skipping 10 matching lines...) Expand all
248 */ 293 */
249 class CacheEntry { 294 class CacheEntry {
250 /** 295 /**
251 * The index of the flag indicating whether the source was explicitly added to 296 * The index of the flag indicating whether the source was explicitly added to
252 * the context or whether the source was implicitly added because it was 297 * the context or whether the source was implicitly added because it was
253 * referenced by another source. 298 * referenced by another source.
254 */ 299 */
255 static int _EXPLICITLY_ADDED_FLAG = 0; 300 static int _EXPLICITLY_ADDED_FLAG = 0;
256 301
257 /** 302 /**
258 * The next invalidation process identifier. 303 * The next visit process identifier.
259 */ 304 */
260 static int nextInvalidateId = 0; 305 static int nextVisitId = 0;
306
307 /**
308 * A table containing the number of times the value of a result descriptor was
309 * recomputed after having been flushed.
310 */
311 static final Map<ResultDescriptor, int> recomputedCounts =
312 new HashMap<ResultDescriptor, int>();
261 313
262 /** 314 /**
263 * The target this entry is about. 315 * The target this entry is about.
264 */ 316 */
265 final AnalysisTarget target; 317 final AnalysisTarget target;
266 318
267 /** 319 /**
268 * The partition that is responsible for this entry. 320 * The partition that is responsible for this entry.
269 */ 321 */
270 CachePartition _partition; 322 CachePartition _partition;
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 /** 370 /**
319 * Return a list of result descriptors for results whose state is not 371 * Return a list of result descriptors for results whose state is not
320 * [CacheState.INVALID]. 372 * [CacheState.INVALID].
321 */ 373 */
322 List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList(); 374 List<ResultDescriptor> get nonInvalidResults => _resultMap.keys.toList();
323 375
324 /** 376 /**
325 * Notifies the entry that the client is going to stop using it. 377 * Notifies the entry that the client is going to stop using it.
326 */ 378 */
327 void dispose() { 379 void dispose() {
328 _resultMap.forEach((descriptor, data) { 380 _resultMap.forEach((ResultDescriptor descriptor, ResultData data) {
329 TargetedResult result = new TargetedResult(target, descriptor); 381 TargetedResult result = new TargetedResult(target, descriptor);
330 for (TargetedResult dependedOnResult in data.dependedOnResults) { 382 for (TargetedResult dependedOnResult in data.dependedOnResults) {
331 ResultData dependedOnData = _partition._getDataFor(dependedOnResult); 383 for (AnalysisCache cache in _partition.containingCaches) {
332 if (dependedOnData != null) { 384 CacheEntry entry = cache.get(dependedOnResult.target);
333 dependedOnData.dependentResults.remove(result); 385 if (entry != null) {
386 ResultData data =
387 entry.getResultDataOrNull(dependedOnResult.result);
388 if (data != null) {
389 data.dependentResults.remove(result);
390 }
391 }
334 } 392 }
335 } 393 }
336 }); 394 });
337 _resultMap.clear(); 395 _resultMap.clear();
338 } 396 }
339 397
340 /** 398 /**
341 * Fix the state of the [exception] to match the current state of the entry. 399 * Fix the state of the [exception] to match the current state of the entry.
342 */ 400 */
343 void fixExceptionState() { 401 void fixExceptionState() {
344 if (!hasErrorState()) { 402 if (!hasErrorState()) {
345 _exception = null; 403 _exception = null;
346 } 404 }
347 } 405 }
348 406
349 /** 407 /**
350 * Look up the [ResultData] of [descriptor], or add a new one if it isn't 408 * Flush results that satisfy the given [filter].
351 * there. 409 */
410 void flush(FlushResultFilter filter) {
411 _resultMap.forEach((ResultDescriptor result, ResultData data) {
412 if (filter(target, result)) {
413 data.flush();
414 }
415 });
416 }
417
418 /**
419 * Return the result data associated with the [descriptor], creating one if it
420 * isn't there.
352 */ 421 */
353 ResultData getResultData(ResultDescriptor descriptor) { 422 ResultData getResultData(ResultDescriptor descriptor) {
354 return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor)); 423 return _resultMap.putIfAbsent(descriptor, () => new ResultData(descriptor));
355 } 424 }
356 425
357 /** 426 /**
427 * Return the result data associated with the [descriptor], or `null` if there
428 * is no data currently associated with the descriptor.
429 */
430 ResultData getResultDataOrNull(ResultDescriptor descriptor) =>
431 _resultMap[descriptor];
432
433 /**
358 * Return the state of the result represented by the given [descriptor]. 434 * Return the state of the result represented by the given [descriptor].
359 */ 435 */
360 CacheState getState(ResultDescriptor descriptor) { 436 CacheState getState(ResultDescriptor descriptor) {
361 ResultData data = _resultMap[descriptor]; 437 ResultData data = _resultMap[descriptor];
362 if (data == null) { 438 if (data == null) {
363 return CacheState.INVALID; 439 return CacheState.INVALID;
364 } 440 }
365 return data.state; 441 return data.state;
366 } 442 }
367 443
368 /** 444 /**
369 * Return the value of the result represented by the given [descriptor], or 445 * Return the value of the result represented by the given [descriptor], or
370 * the default value for the result if this entry does not have a valid value. 446 * the default value for the result if this entry does not have a valid value.
371 */ 447 */
372 /*<V>*/ dynamic /*V*/ getValue(ResultDescriptor /*<V>*/ descriptor) { 448 dynamic/*=V*/ getValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor) {
373 ResultData data = _resultMap[descriptor]; 449 ResultData data = _resultMap[descriptor];
374 if (data == null) { 450 if (data == null) {
375 return descriptor.defaultValue; 451 return descriptor.defaultValue;
376 } 452 }
377 if (_partition != null) { 453 if (_partition != null) {
378 _partition.resultAccessed(target, descriptor); 454 _partition.resultAccessed(target, descriptor);
379 } 455 }
380 return data.value; 456 return data.value as Object/*=V*/;
381 } 457 }
382 458
383 /** 459 /**
384 * Return `true` if the state of any data value is [CacheState.ERROR]. 460 * Return `true` if the state of any data value is [CacheState.ERROR].
385 */ 461 */
386 bool hasErrorState() { 462 bool hasErrorState() {
387 for (ResultData data in _resultMap.values) { 463 for (ResultData data in _resultMap.values) {
388 if (data.state == CacheState.ERROR) { 464 if (data.state == CacheState.ERROR) {
389 return true; 465 return true;
390 } 466 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 if (state == CacheState.ERROR) { 517 if (state == CacheState.ERROR) {
442 throw new ArgumentError('use setErrorState() to set the state to ERROR'); 518 throw new ArgumentError('use setErrorState() to set the state to ERROR');
443 } 519 }
444 if (state == CacheState.VALID) { 520 if (state == CacheState.VALID) {
445 throw new ArgumentError('use setValue() to set the state to VALID'); 521 throw new ArgumentError('use setValue() to set the state to VALID');
446 } 522 }
447 _validateStateChange(descriptor, state); 523 _validateStateChange(descriptor, state);
448 if (state == CacheState.INVALID) { 524 if (state == CacheState.INVALID) {
449 ResultData data = _resultMap[descriptor]; 525 ResultData data = _resultMap[descriptor];
450 if (data != null) { 526 if (data != null) {
451 _invalidate(nextInvalidateId++, descriptor, delta, 0); 527 bool canUseDelta =
528 _gatherResultsInvalidatedByDelta(descriptor, delta, 0);
529 if (!canUseDelta) {
530 delta = null;
531 }
532 _invalidate(nextVisitId++, descriptor, delta, 0);
452 } 533 }
453 } else { 534 } else {
454 ResultData data = getResultData(descriptor); 535 ResultData data = getResultData(descriptor);
455 data.state = state; 536 data.state = state;
456 if (state != CacheState.IN_PROCESS) { 537 if (state != CacheState.IN_PROCESS) {
457 // 538 //
458 // If the state is in-process, we can leave the current value in the 539 // If the state is in-process, we can leave the current value in the
459 // cache for any 'get' methods to access. 540 // cache for any 'get' methods to access.
460 // 541 //
461 data.value = descriptor.defaultValue; 542 data.value = descriptor.defaultValue;
462 } 543 }
463 } 544 }
464 } 545 }
465 546
466 /** 547 /**
467 * Set the value of the result represented by the given [descriptor] to the 548 * Set the value of the result represented by the given [descriptor] to the
468 * given [value]. 549 * given [value].
469 */ 550 */
470 /*<V>*/ void setValue( 551 void setValue/*<V>*/(ResultDescriptor/*<V>*/ descriptor, dynamic/*=V*/ value,
471 ResultDescriptor /*<V>*/ descriptor,
472 dynamic /*V*/
473 value,
474 List<TargetedResult> dependedOn) { 552 List<TargetedResult> dependedOn) {
475 // { 553 // {
476 // String valueStr = '$value'; 554 // String valueStr = '$value';
477 // if (valueStr.length > 20) { 555 // if (valueStr.length > 20) {
478 // valueStr = valueStr.substring(0, 20) + '...'; 556 // valueStr = valueStr.substring(0, 20) + '...';
479 // } 557 // }
480 // valueStr = valueStr.replaceAll('\n', '\\n'); 558 // valueStr = valueStr.replaceAll('\n', '\\n');
481 // print( 559 // print(
482 // 'setValue $descriptor for $target value=$valueStr deps=$dependedOn') ; 560 // 'setValue $descriptor for $target value=$valueStr dependedOn=$depend edOn');
483 // } 561 // }
484 _validateStateChange(descriptor, CacheState.VALID); 562 _validateStateChange(descriptor, CacheState.VALID);
485 TargetedResult thisResult = new TargetedResult(target, descriptor); 563 TargetedResult thisResult = new TargetedResult(target, descriptor);
486 if (_partition != null) { 564 if (_partition != null) {
487 _partition.resultStored(thisResult, value); 565 _partition.resultStored(thisResult, value);
488 } 566 }
489 ResultData data = getResultData(descriptor); 567 ResultData data = getResultData(descriptor);
490 _setDependedOnResults(data, thisResult, dependedOn); 568 _setDependedOnResults(data, thisResult, dependedOn);
569 if (data.state == CacheState.FLUSHED) {
570 int count = recomputedCounts[descriptor] ?? 0;
571 recomputedCounts[descriptor] = count + 1;
572 }
491 data.state = CacheState.VALID; 573 data.state = CacheState.VALID;
492 data.value = value == null ? descriptor.defaultValue : value; 574 data.value = value ?? descriptor.defaultValue;
493 } 575 }
494 576
495 /** 577 /**
496 * Set the value of the result represented by the given [descriptor] to the 578 * If the result represented by the given [descriptor] is valid, set
497 * given [value], keep its dependency, invalidate all the dependent result. 579 * it to the given [value], keep its dependency, and if [invalidateDependent]
580 * invalidate all the dependent result.
498 */ 581 */
499 void setValueIncremental( 582 void setValueIncremental(
500 ResultDescriptor descriptor, dynamic value, bool invalidateDependent) { 583 ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
501 ResultData data = getResultData(descriptor); 584 ResultData data = getResultData(descriptor);
502 data.state = CacheState.VALID; 585 if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
503 data.value = value; 586 data.value = value;
587 }
504 if (invalidateDependent) { 588 if (invalidateDependent) {
505 _invalidateDependentResults(nextInvalidateId++, data, null, 0); 589 _invalidateDependentResults(nextVisitId++, data, null, 0);
506 } 590 }
507 } 591 }
508 592
509 @override 593 @override
510 String toString() { 594 String toString() {
511 StringBuffer buffer = new StringBuffer(); 595 StringBuffer buffer = new StringBuffer();
512 _writeOn(buffer); 596 _writeOn(buffer);
513 return buffer.toString(); 597 return buffer.toString();
514 } 598 }
515 599
516 /** 600 /**
601 * Visit the given [result] and all results that depend on it, and
602 * ask [delta] to gather changes. Return `true` if the [delta] can be used
603 * to perform limited invalidation, or `false` if the changes collection
604 * process does not stop (should not happen).
605 */
606 bool _gatherResultsInvalidatedByDelta(
607 ResultDescriptor result, Delta delta, int level) {
608 if (delta == null) {
609 return false;
610 }
611 if (!delta.shouldGatherChanges) {
612 return true;
613 }
614 for (int i = 0; i < 64; i++) {
615 bool hasVisitChanges = false;
616 _visitResults(nextVisitId++, result,
617 (AnalysisTarget target, ResultData data) {
618 bool hasDeltaChanges = delta.gatherChanges(
619 _partition.context, target, data.descriptor, data.value);
620 if (hasDeltaChanges) {
621 hasVisitChanges = true;
622 }
623 });
624 delta.gatherEnd();
625 if (!hasVisitChanges) {
626 return true;
627 }
628 }
629 return false;
630 }
631
632 /**
517 * Return the value of the flag with the given [index]. 633 * Return the value of the flag with the given [index].
518 */ 634 */
519 bool _getFlag(int index) => BooleanArray.get(_flags, index); 635 bool _getFlag(int index) => BooleanArray.get(_flags, index);
520 636
521 /** 637 /**
522 * Invalidate the result represented by the given [descriptor] and propagate 638 * Invalidate the result represented by the given [descriptor] and propagate
523 * invalidation to other results that depend on it. 639 * invalidation to other results that depend on it.
524 */ 640 */
525 void _invalidate( 641 void _invalidate(
526 int id, ResultDescriptor descriptor, Delta delta, int level) { 642 int id, ResultDescriptor descriptor, Delta delta, int level) {
527 ResultData thisData = _resultMap[descriptor]; 643 ResultData thisData = _resultMap[descriptor];
528 if (thisData == null) { 644 if (thisData == null) {
529 return; 645 return;
530 } 646 }
531 // Stop if already validated. 647 // Stop if already validated.
532 if (delta != null) { 648 if (delta != null) {
533 if (thisData.invalidateId == id) { 649 if (thisData.visitId == id) {
534 return; 650 return;
535 } 651 }
536 thisData.invalidateId = id; 652 thisData.visitId = id;
537 } 653 }
538 // Ask the delta to validate. 654 // Ask the delta to validate.
539 DeltaResult deltaResult = null; 655 DeltaResult deltaResult = null;
540 if (delta != null) { 656 if (delta != null) {
541 deltaResult = delta.validate(_partition.context, target, descriptor); 657 deltaResult = delta.validate(
658 _partition.context, target, descriptor, thisData.value);
542 if (deltaResult == DeltaResult.STOP) { 659 if (deltaResult == DeltaResult.STOP) {
543 return; 660 return;
544 } 661 }
545 } 662 }
663 // if (deltaResult != null) {
664 // String indent = ' ' * level;
665 // String deltaResultName = deltaResult.toString().split('.').last;
666 // print('[$id]$indent$deltaResultName $descriptor for $target');
667 // }
546 if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) { 668 if (deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
547 delta = null; 669 delta = null;
548 } 670 }
549 if (deltaResult == null || 671 if (deltaResult == DeltaResult.INVALIDATE_KEEP_DEPENDENCIES) {
672 thisData.value = descriptor.defaultValue;
673 thisData.state = CacheState.INVALID;
674 } else if (deltaResult == null ||
550 deltaResult == DeltaResult.INVALIDATE || 675 deltaResult == DeltaResult.INVALIDATE ||
551 deltaResult == DeltaResult.INVALIDATE_NO_DELTA) { 676 deltaResult == DeltaResult.INVALIDATE_NO_DELTA) {
552 _resultMap.remove(descriptor); 677 _resultMap.remove(descriptor);
553 // { 678 // Stop depending on other results.
679 {
680 TargetedResult thisResult = new TargetedResult(target, descriptor);
681 List<AnalysisCache> caches = _partition.containingCaches;
682 int cacheLength = caches.length;
683 List<TargetedResult> results = thisData.dependedOnResults;
684 int resultLength = results.length;
685 for (int i = 0; i < resultLength; i++) {
686 TargetedResult dependedOnResult = results[i];
687 for (int j = 0; j < cacheLength; j++) {
688 AnalysisCache cache = caches[j];
689 CacheEntry entry = cache.get(dependedOnResult.target);
690 if (entry != null) {
691 ResultData data =
692 entry.getResultDataOrNull(dependedOnResult.result);
693 if (data != null) {
694 data.dependentResults.remove(thisResult);
695 }
696 }
697 }
698 }
699 }
700 // if (deltaResult == null) {
554 // String indent = ' ' * level; 701 // String indent = ' ' * level;
555 // print('[$id]$indent invalidate $descriptor for $target'); 702 // print('[$id]$indent invalidate $descriptor for $target');
556 // } 703 // }
557 } 704 }
558 // Stop depending on other results.
559 TargetedResult thisResult = new TargetedResult(target, descriptor);
560 for (TargetedResult dependedOnResult in thisData.dependedOnResults) {
561 ResultData data = _partition._getDataFor(dependedOnResult);
562 if (data != null && deltaResult != DeltaResult.KEEP_CONTINUE) {
563 data.dependentResults.remove(thisResult);
564 }
565 }
566 // Invalidate results that depend on this result. 705 // Invalidate results that depend on this result.
567 _invalidateDependentResults(id, thisData, delta, level + 1); 706 _invalidateDependentResults(id, thisData, delta, level + 1);
568 // If empty, remove the entry altogether. 707 // If empty and not explicitly added, remove the entry altogether.
569 if (_resultMap.isEmpty) { 708 if (_resultMap.isEmpty && !explicitlyAdded) {
570 _partition._targetMap.remove(target); 709 CacheEntry entry = _partition.entryMap.remove(target);
710 if (entry != null) {
711 entry.dispose();
712 }
571 _partition._removeIfSource(target); 713 _partition._removeIfSource(target);
572 } 714 }
573 // Notify controller. 715 // Notify controller.
574 _partition.onResultInvalidated 716 if (deltaResult != DeltaResult.KEEP_CONTINUE) {
575 .add(new InvalidatedResult(this, descriptor, thisData.value)); 717 _partition.onResultInvalidated
718 .add(new InvalidatedResult(this, descriptor, thisData.value));
719 }
576 } 720 }
577 721
578 /** 722 /**
579 * Invalidates all the results of this entry, with propagation. 723 * Invalidates all the results of this entry, with propagation.
580 */ 724 */
581 void _invalidateAll() { 725 void _invalidateAll() {
582 List<ResultDescriptor> results = _resultMap.keys.toList(); 726 List<ResultDescriptor> results = _resultMap.keys.toList();
583 for (ResultDescriptor result in results) { 727 int length = results.length;
584 _invalidate(nextInvalidateId++, result, null, 0); 728 for (int i = 0; i < length; i++) {
729 ResultDescriptor result = results[i];
730 _invalidate(nextVisitId++, result, null, 0);
585 } 731 }
586 } 732 }
587 733
588 /** 734 /**
589 * Invalidate results that depend on [thisData]. 735 * Invalidate results that depend on [thisData].
590 */ 736 */
591 void _invalidateDependentResults( 737 void _invalidateDependentResults(
592 int id, ResultData thisData, Delta delta, int level) { 738 int id, ResultData thisData, Delta delta, int level) {
739 // It is necessary to copy the results to a list to avoid a concurrent
740 // modification of the set of dependent results.
741 List<AnalysisCache> caches = _partition.containingCaches;
742 int cacheLength = caches.length;
593 List<TargetedResult> dependentResults = thisData.dependentResults.toList(); 743 List<TargetedResult> dependentResults = thisData.dependentResults.toList();
594 for (TargetedResult dependentResult in dependentResults) { 744 int resultLength = dependentResults.length;
595 CacheEntry entry = _partition.get(dependentResult.target); 745 for (int i = 0; i < resultLength; i++) {
596 if (entry != null) { 746 TargetedResult dependentResult = dependentResults[i];
597 entry._invalidate(id, dependentResult.result, delta, level); 747 for (int j = 0; j < cacheLength; j++) {
748 AnalysisCache cache = caches[j];
749 CacheEntry entry = cache.get(dependentResult.target);
750 if (entry != null) {
751 entry._invalidate(id, dependentResult.result, delta, level);
752 }
598 } 753 }
599 } 754 }
600 } 755 }
601 756
602 /** 757 /**
603 * Set the [dependedOn] on which this result depends. 758 * Set the [dependedOn] on which this result depends.
604 */ 759 */
605 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult, 760 void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
606 List<TargetedResult> dependedOn) { 761 List<TargetedResult> dependedOn) {
607 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { 762 List<AnalysisCache> caches = _partition.containingCaches;
608 ResultData data = _partition._getDataFor(dependedOnResult); 763 int cacheLength = caches.length;
609 if (data != null) { 764
610 data.dependentResults.remove(thisResult); 765 List<TargetedResult> oldResults = thisData.dependedOnResults;
766 int oldLength = oldResults.length;
767 for (int i = 0; i < oldLength; i++) {
768 TargetedResult dependedOnResult = oldResults[i];
769 for (int j = 0; j < cacheLength; j++) {
770 AnalysisCache cache = caches[j];
771 CacheEntry entry = cache.get(dependedOnResult.target);
772 if (entry != null) {
773 ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
774 if (data != null) {
775 data.dependentResults.remove(thisResult);
776 }
777 }
611 } 778 }
612 }); 779 }
613 thisData.dependedOnResults = dependedOn; 780 thisData.dependedOnResults = dependedOn;
614 thisData.dependedOnResults.forEach((TargetedResult dependedOnResult) { 781 int newLength = dependedOn.length;
615 ResultData data = _partition._getDataFor(dependedOnResult); 782 for (int i = 0; i < newLength; i++) {
616 if (data != null) { 783 TargetedResult dependedOnResult = dependedOn[i];
617 data.dependentResults.add(thisResult); 784 for (int j = 0; j < cacheLength; j++) {
785 AnalysisCache cache = caches[j];
786 CacheEntry entry = cache.get(dependedOnResult.target);
787 if (entry != null) {
788 ResultData data = entry.getResultData(dependedOnResult.result);
789 data.dependentResults.add(thisResult);
790 }
618 } 791 }
619 }); 792 }
620 } 793 }
621 794
622 /** 795 /**
623 * Set states of the given and dependent results to [CacheState.ERROR] and 796 * Set states of the given and dependent results to [CacheState.ERROR] and
624 * their values to the corresponding default values 797 * their values to the corresponding default values
625 */ 798 */
626 void _setErrorState(ResultDescriptor descriptor, CaughtException exception) { 799 void _setErrorState(ResultDescriptor descriptor, CaughtException exception) {
627 ResultData thisData = getResultData(descriptor); 800 ResultData thisData = getResultData(descriptor);
628 // Set the error state. 801 // Set the error state.
629 _exception = exception; 802 _exception = exception;
630 thisData.state = CacheState.ERROR; 803 thisData.state = CacheState.ERROR;
631 thisData.value = descriptor.defaultValue; 804 thisData.value = descriptor.defaultValue;
632 // Propagate the error state. 805 // Propagate the error state.
806 List<AnalysisCache> caches = _partition.containingCaches;
807 int cacheLength = caches.length;
633 thisData.dependentResults.forEach((TargetedResult dependentResult) { 808 thisData.dependentResults.forEach((TargetedResult dependentResult) {
634 CacheEntry entry = _partition.get(dependentResult.target); 809 for (int i = 0; i < cacheLength; i++) {
635 entry._setErrorState(dependentResult.result, exception); 810 AnalysisCache cache = caches[i];
811 CacheEntry entry = cache.get(dependentResult.target);
812 if (entry != null) {
813 entry._setErrorState(dependentResult.result, exception);
814 }
815 }
636 }); 816 });
637 } 817 }
638 818
639 /** 819 /**
640 * Set the value of the flag with the given [index] to the given [value]. 820 * Set the value of the flag with the given [index] to the given [value].
641 */ 821 */
642 void _setFlag(int index, bool value) { 822 void _setFlag(int index, bool value) {
643 _flags = BooleanArray.set(_flags, index, value); 823 _flags = BooleanArray.set(_flags, index, value);
644 } 824 }
645 825
(...skipping 14 matching lines...) Expand all
660 // InstrumentationBuilder builder = 840 // InstrumentationBuilder builder =
661 // Instrumentation.builder2('CacheEntry-validateStateChange'); 841 // Instrumentation.builder2('CacheEntry-validateStateChange');
662 // builder.data3('message', message); 842 // builder.data3('message', message);
663 // //builder.data('source', source.getFullName()); 843 // //builder.data('source', source.getFullName());
664 // builder.record(new CaughtException(new AnalysisException(message), null) ); 844 // builder.record(new CaughtException(new AnalysisException(message), null) );
665 // builder.log(); 845 // builder.log();
666 // } 846 // }
667 } 847 }
668 848
669 /** 849 /**
850 * Call [visitor] for the result described by the given [descriptor] and all
851 * results that depend on directly or indirectly. Each result is visited
852 * only once.
853 */
854 void _visitResults(
855 int id, ResultDescriptor descriptor, CacheResultVisitor visitor) {
856 ResultData thisData = _resultMap[descriptor];
857 if (thisData == null) {
858 return;
859 }
860 // Stop if already visited.
861 if (thisData.visitId == id) {
862 return;
863 }
864 thisData.visitId = id;
865 // Visit this result.
866 visitor(target, thisData);
867 // Visit results that depend on this result.
868 List<AnalysisCache> caches = _partition.containingCaches;
869 int cacheLength = caches.length;
870 List<TargetedResult> dependentResults = thisData.dependentResults.toList();
871 int resultLength = dependentResults.length;
872 for (int i = 0; i < resultLength; i++) {
873 TargetedResult dependentResult = dependentResults[i];
874 for (int j = 0; j < cacheLength; j++) {
875 AnalysisCache cache = caches[j];
876 CacheEntry entry = cache.get(dependentResult.target);
877 if (entry != null) {
878 entry._visitResults(id, dependentResult.result, visitor);
879 }
880 }
881 }
882 }
883
884 /**
670 * Write a textual representation of this entry to the given [buffer]. The 885 * Write a textual representation of this entry to the given [buffer]. The
671 * result should only be used for debugging purposes. 886 * result should only be used for debugging purposes.
672 */ 887 */
673 void _writeOn(StringBuffer buffer) { 888 void _writeOn(StringBuffer buffer) {
674 buffer.write('time = '); 889 buffer.write('time = ');
675 buffer.write(modificationTime); 890 buffer.write(modificationTime);
676 List<ResultDescriptor> results = _resultMap.keys.toList(); 891 List<ResultDescriptor> results = _resultMap.keys.toList();
677 results.sort((ResultDescriptor first, ResultDescriptor second) => 892 results.sort((ResultDescriptor first, ResultDescriptor second) =>
678 first.toString().compareTo(second.toString())); 893 first.toString().compareTo(second.toString()));
679 for (ResultDescriptor result in results) { 894 for (ResultDescriptor result in results) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 /** 933 /**
719 * The current maximum cache size. 934 * The current maximum cache size.
720 */ 935 */
721 int maxSize; 936 int maxSize;
722 937
723 CacheFlushManager( 938 CacheFlushManager(
724 ResultCachingPolicy<T> policy, this.isPriorityAnalysisTarget) 939 ResultCachingPolicy<T> policy, this.isPriorityAnalysisTarget)
725 : policy = policy, 940 : policy = policy,
726 maxActiveSize = policy.maxActiveSize, 941 maxActiveSize = policy.maxActiveSize,
727 maxIdleSize = policy.maxIdleSize, 942 maxIdleSize = policy.maxIdleSize,
728 maxSize = policy.maxIdleSize; 943 maxSize = policy.maxActiveSize;
729 944
730 /** 945 /**
731 * If [currentSize] is already less than [maxSize], returns an empty list. 946 * If [currentSize] is already less than [maxSize], returns an empty list.
732 * Otherwise returns [TargetedResult]s to flush from the cache to make 947 * Otherwise returns [TargetedResult]s to flush from the cache to make
733 * [currentSize] less or equal to [maxSize]. 948 * [currentSize] less or equal to [maxSize].
734 * 949 *
735 * Results for priority files are never flushed, so this method might leave 950 * Results for priority files are never flushed, so this method might leave
736 * [currentSize] greater than [maxSize]. 951 * [currentSize] greater than [maxSize].
737 */ 952 */
738 List<TargetedResult> flushToSize() { 953 List<TargetedResult> flushToSize() {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 * A single partition in an LRU cache of information related to analysis. 1033 * A single partition in an LRU cache of information related to analysis.
819 */ 1034 */
820 abstract class CachePartition { 1035 abstract class CachePartition {
821 /** 1036 /**
822 * The context that owns this partition. Multiple contexts can reference a 1037 * The context that owns this partition. Multiple contexts can reference a
823 * partition, but only one context can own it. 1038 * partition, but only one context can own it.
824 */ 1039 */
825 final InternalAnalysisContext context; 1040 final InternalAnalysisContext context;
826 1041
827 /** 1042 /**
1043 * A list of the caches that contain this partition. This includes the cache
1044 * associated with the context that owns this partition.
1045 */
1046 final List<AnalysisCache> containingCaches = <AnalysisCache>[];
1047
1048 /**
828 * A table mapping caching policies to the cache flush managers. 1049 * A table mapping caching policies to the cache flush managers.
829 */ 1050 */
830 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap = 1051 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap =
831 new HashMap<ResultCachingPolicy, CacheFlushManager>(); 1052 new HashMap<ResultCachingPolicy, CacheFlushManager>();
832 1053
833 /** 1054 /**
834 * The [StreamController] reporting [InvalidatedResult]s. 1055 * The [StreamController] reporting [InvalidatedResult]s.
835 */ 1056 */
836 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated = 1057 final ReentrantSynchronousStream<InvalidatedResult> onResultInvalidated =
837 new ReentrantSynchronousStream<InvalidatedResult>(); 1058 new ReentrantSynchronousStream<InvalidatedResult>();
838 1059
839 /** 1060 /**
840 * A table mapping the targets belonging to this partition to the information 1061 * A table mapping the targets belonging to this partition to the information
841 * known about those targets. 1062 * known about those targets.
842 */ 1063 */
843 HashMap<AnalysisTarget, CacheEntry> _targetMap = 1064 final HashMap<AnalysisTarget, CacheEntry> entryMap =
844 new HashMap<AnalysisTarget, CacheEntry>(); 1065 new HashMap<AnalysisTarget, CacheEntry>();
845 1066
846 /** 1067 /**
847 * A set of the [Source] targets. 1068 * A set of the [Source] targets.
848 */ 1069 */
849 final HashSet<Source> _sources = new HashSet<Source>(); 1070 final HashSet<Source> sources = new HashSet<Source>();
850 1071
851 /** 1072 /**
852 * A table mapping full paths to lists of [Source]s with these full paths. 1073 * A table mapping full paths to lists of [Source]s with these full paths.
853 */ 1074 */
854 final Map<String, List<Source>> _pathToSources = <String, List<Source>>{}; 1075 final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
855 1076
856 /** 1077 /**
857 * Initialize a newly created cache partition, belonging to the given 1078 * Initialize a newly created cache partition, belonging to the given
858 * [context]. 1079 * [context].
859 */ 1080 */
860 CachePartition(this.context); 1081 CachePartition(this.context);
861 1082
862 /** 1083 /**
863 * Return a table mapping the targets known to the context to the information 1084 * Specify whether a context that uses this partition is being analyzed.
864 * known about the target.
865 *
866 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and
867 * should not be used for any other purpose.
868 */ 1085 */
869 Map<AnalysisTarget, CacheEntry> get map => _targetMap; 1086 set isActive(bool active) {
1087 for (CacheFlushManager manager in _flushManagerMap.values) {
1088 if (active) {
1089 manager.madeActive();
1090 } else {
1091 List<TargetedResult> resultsToFlush = manager.madeIdle();
1092 _flushResults(resultsToFlush);
1093 }
1094 }
1095 }
870 1096
871 /** 1097 /**
872 * Notifies the partition that the client is going to stop using it. 1098 * Notifies the partition that the client is going to stop using it.
873 */ 1099 */
874 void dispose() { 1100 void dispose() {
875 for (CacheEntry entry in _targetMap.values) { 1101 for (CacheEntry entry in entryMap.values) {
876 entry.dispose(); 1102 entry.dispose();
877 } 1103 }
878 _targetMap.clear(); 1104 entryMap.clear();
1105 sources.clear();
1106 pathToSource.clear();
1107 }
1108
1109 /**
1110 * Flush results that satisfy the given [filter].
1111 */
1112 void flush(FlushResultFilter filter) {
1113 for (CacheEntry entry in entryMap.values) {
1114 entry.flush(filter);
1115 }
879 } 1116 }
880 1117
881 /** 1118 /**
882 * Return the entry associated with the given [target]. 1119 * Return the entry associated with the given [target].
883 */ 1120 */
884 CacheEntry get(AnalysisTarget target) => _targetMap[target]; 1121 CacheEntry get(AnalysisTarget target) => entryMap[target];
885 1122
886 /** 1123 /**
887 * Return [Source]s whose full path is equal to the given [path]. 1124 * Return [Source]s whose full path is equal to the given [path].
888 * Maybe empty, but not `null`. 1125 * Maybe empty, but not `null`.
889 */ 1126 */
890 List<Source> getSourcesWithFullName(String path) { 1127 List<Source> getSourcesWithFullName(String path) {
891 List<Source> sources = _pathToSources[path]; 1128 List<Source> sources = pathToSource[path];
892 return sources != null ? sources : Source.EMPTY_LIST; 1129 return sources ?? Source.EMPTY_LIST;
893 } 1130 }
894 1131
895 /** 1132 /**
896 * Return `true` if this partition is responsible for the given [target]. 1133 * Return `true` if this partition is responsible for the given [target].
897 */ 1134 */
898 bool isResponsibleFor(AnalysisTarget target); 1135 bool isResponsibleFor(AnalysisTarget target);
899 1136
900 /** 1137 /**
901 * Return an iterator returning all of the map entries mapping targets to 1138 * Return an iterator returning all of the map entries mapping targets to
902 * cache entries. 1139 * cache entries.
903 */ 1140 */
904 MapIterator<AnalysisTarget, CacheEntry> iterator() => 1141 MapIterator<AnalysisTarget, CacheEntry> iterator() =>
905 new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap); 1142 new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
906 1143
907 /** 1144 /**
908 * Puts the given [entry] into the partition. 1145 * Puts the given [entry] into the partition.
909 */ 1146 */
910 void put(CacheEntry entry) { 1147 void put(CacheEntry entry) {
911 AnalysisTarget target = entry.target; 1148 AnalysisTarget target = entry.target;
912 if (entry._partition != null) { 1149 if (entry._partition != null) {
913 throw new StateError( 1150 throw new StateError(
914 'The entry for $target is already in ${entry._partition}'); 1151 'The entry for $target is already in ${entry._partition}');
915 } 1152 }
916 entry._partition = this; 1153 entry._partition = this;
917 entry.fixExceptionState(); 1154 entry.fixExceptionState();
918 _targetMap[target] = entry; 1155 entryMap[target] = entry;
919 _addIfSource(target); 1156 _addIfSource(target);
920 } 1157 }
921 1158
922 /** 1159 /**
923 * Remove all information related to the given [target] from this partition. 1160 * Remove all information related to the given [target] from this partition.
924 * Return the entry associated with the target, or `null` if there was cache 1161 * Return the entry associated with the target, or `null` if there was cache
925 * entry for the target. 1162 * entry for the target.
926 */ 1163 */
927 CacheEntry remove(AnalysisTarget target) { 1164 CacheEntry remove(AnalysisTarget target) {
928 for (CacheFlushManager flushManager in _flushManagerMap.values) { 1165 for (CacheFlushManager flushManager in _flushManagerMap.values) {
929 flushManager.targetRemoved(target); 1166 flushManager.targetRemoved(target);
930 } 1167 }
931 CacheEntry entry = _targetMap.remove(target); 1168 CacheEntry entry = entryMap.remove(target);
932 if (entry != null) { 1169 if (entry != null) {
933 entry._invalidateAll(); 1170 entry._invalidateAll();
934 } 1171 }
935 _removeIfSource(target); 1172 _removeIfSource(target);
936 return entry; 1173 return entry;
937 } 1174 }
938 1175
939 /** 1176 /**
940 * Records that a value of the result described by the given [descriptor] 1177 * Records that a value of the result described by the given [descriptor]
941 * for the given [target] was just read from the cache. 1178 * for the given [target] was just read from the cache.
942 */ 1179 */
943 void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) { 1180 void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) {
944 CacheFlushManager flushManager = _getFlushManager(descriptor); 1181 CacheFlushManager flushManager = _getFlushManager(descriptor);
945 TargetedResult result = new TargetedResult(target, descriptor); 1182 TargetedResult result = new TargetedResult(target, descriptor);
946 flushManager.resultAccessed(result); 1183 flushManager.resultAccessed(result);
947 } 1184 }
948 1185
949 /** 1186 /**
950 * Records that the given [result] was just stored into the cache. 1187 * Records that the given [result] was just stored into the cache.
951 */ 1188 */
952 void resultStored(TargetedResult result, Object value) { 1189 void resultStored(TargetedResult result, Object value) {
953 CacheFlushManager flushManager = _getFlushManager(result.result); 1190 CacheFlushManager flushManager = _getFlushManager(result.result);
954 List<TargetedResult> resultsToFlush = 1191 List<TargetedResult> resultsToFlush =
955 flushManager.resultStored(result, value); 1192 flushManager.resultStored(result, value);
1193 _flushResults(resultsToFlush);
1194 }
1195
1196 /**
1197 * Return the number of targets that are mapped to cache entries.
1198 */
1199 int size() => entryMap.length;
1200
1201 /**
1202 * If the given [target] is a [Source], adds it to [sources].
1203 */
1204 void _addIfSource(AnalysisTarget target) {
1205 if (target is Source) {
1206 sources.add(target);
1207 String fullName = target.fullName;
1208 pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
1209 }
1210 }
1211
1212 /**
1213 * Flush the given [resultsToFlush].
1214 */
1215 void _flushResults(List<TargetedResult> resultsToFlush) {
956 for (TargetedResult result in resultsToFlush) { 1216 for (TargetedResult result in resultsToFlush) {
957 CacheEntry entry = get(result.target); 1217 CacheEntry entry = get(result.target);
958 if (entry != null) { 1218 if (entry != null) {
959 ResultData data = entry._resultMap[result.result]; 1219 ResultData data = entry._resultMap[result.result];
960 if (data != null) { 1220 if (data != null) {
961 data.flush(); 1221 data.flush();
962 } 1222 }
963 } 1223 }
964 } 1224 }
965 } 1225 }
966 1226
967 /** 1227 /**
968 * Return the number of targets that are mapped to cache entries.
969 */
970 int size() => _targetMap.length;
971
972 /**
973 * If the given [target] is a [Source], adds it to [_sources].
974 */
975 void _addIfSource(AnalysisTarget target) {
976 if (target is Source) {
977 _sources.add(target);
978 String fullName = target.fullName;
979 _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
980 }
981 }
982
983 ResultData _getDataFor(TargetedResult result) {
984 CacheEntry entry = context.analysisCache.get(result.target);
985 return entry != null ? entry._resultMap[result.result] : null;
986 }
987
988 /**
989 * Return the [CacheFlushManager] for the given [descriptor], not `null`. 1228 * Return the [CacheFlushManager] for the given [descriptor], not `null`.
990 */ 1229 */
991 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) { 1230 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) {
992 ResultCachingPolicy policy = descriptor.cachingPolicy; 1231 ResultCachingPolicy policy = descriptor.cachingPolicy;
993 if (identical(policy, DEFAULT_CACHING_POLICY)) { 1232 if (identical(policy, DEFAULT_CACHING_POLICY) ||
1233 context.analysisOptions.disableCacheFlushing) {
994 return UnlimitedCacheFlushManager.INSTANCE; 1234 return UnlimitedCacheFlushManager.INSTANCE;
995 } 1235 }
996 CacheFlushManager manager = _flushManagerMap[policy]; 1236 CacheFlushManager manager = _flushManagerMap[policy];
997 if (manager == null) { 1237 if (manager == null) {
998 manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget); 1238 manager = new CacheFlushManager(policy, _isPriorityAnalysisTarget);
999 _flushManagerMap[policy] = manager; 1239 _flushManagerMap[policy] = manager;
1000 } 1240 }
1001 return manager; 1241 return manager;
1002 } 1242 }
1003 1243
1004 bool _isPriorityAnalysisTarget(AnalysisTarget target) { 1244 bool _isPriorityAnalysisTarget(AnalysisTarget target) {
1005 return context.priorityTargets.contains(target); 1245 Source source = target.source;
1246 return source != null && context.prioritySources.contains(source);
1006 } 1247 }
1007 1248
1008 /** 1249 /**
1009 * If the given [target] is a [Source], remove it from the list of [_sources]. 1250 * If the given [target] is a [Source], remove it from the list of [sources].
1010 */ 1251 */
1011 void _removeIfSource(AnalysisTarget target) { 1252 void _removeIfSource(AnalysisTarget target) {
1012 if (target is Source) { 1253 if (target is Source) {
1013 _sources.remove(target); 1254 sources.remove(target);
1014 String fullName = target.fullName; 1255 String path = target.fullName;
1015 List<Source> sources = _pathToSources[fullName]; 1256 List<Source> pathSources = pathToSource[path];
1016 if (sources != null) { 1257 if (pathSources != null) {
1017 sources.remove(target); 1258 pathSources.remove(target);
1018 if (sources.isEmpty) { 1259 if (pathSources.isEmpty) {
1019 _pathToSources.remove(fullName); 1260 pathToSource.remove(path);
1020 } 1261 }
1021 } 1262 }
1022 } 1263 }
1023 } 1264 }
1024 } 1265 }
1025 1266
1026 /** 1267 /**
1027 * The description for a change. 1268 * The description for a change.
1028 */ 1269 */
1029 class Delta { 1270 class Delta {
1030 final Source source; 1271 final Source source;
1031 1272
1032 Delta(this.source); 1273 Delta(this.source);
1033 1274
1034 /** 1275 /**
1276 * Return `true` if this delta needs cache walking to gather additional
1277 * changes before it can be used to [validate]. In this case [gatherChanges]
1278 * is invoked for every targeted result in transitive dependencies, and
1279 * [gatherEnd] is invoked after cache walking is done.
1280 */
1281 bool get shouldGatherChanges => false;
1282
1283 /**
1284 * This method is called during a cache walk, so that the delta can gather
1285 * additional changes to which are caused by the changes it already knows
1286 * about. Return `true` if a new change was added, so that one more cache
1287 * walk will be performed (to include changes that depend on results which we
1288 * decided to be changed later in the previous cache walk).
1289 */
1290 bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
1291 ResultDescriptor descriptor, Object value) {
1292 return false;
1293 }
1294
1295 /**
1296 * The current cache results visit is done.
1297 */
1298 void gatherEnd() {}
1299
1300 /**
1035 * Check whether this delta affects the result described by the given 1301 * Check whether this delta affects the result described by the given
1036 * [descriptor] and [target]. 1302 * [descriptor] and [target]. The current [value] of the result is provided.
1037 */ 1303 */
1038 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target, 1304 DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
1039 ResultDescriptor descriptor) { 1305 ResultDescriptor descriptor, Object value) {
1040 return DeltaResult.INVALIDATE; 1306 return DeltaResult.INVALIDATE;
1041 } 1307 }
1042 } 1308 }
1043 1309
1044 /** 1310 /**
1045 * The possible results of validating analysis results againt a [Delta]. 1311 * The possible results of validating analysis results against a [Delta].
1046 */ 1312 */
1047 enum DeltaResult { 1313 enum DeltaResult {
1048 /** 1314 /**
1049 * Invalidate this result and continue visiting dependent results 1315 * Invalidate this result and continue visiting dependent results
1050 * with this [Delta]. 1316 * with this [Delta]. Remove the result and all its dependencies.
1051 */ 1317 */
1052 INVALIDATE, 1318 INVALIDATE,
1053 1319
1054 /** 1320 /**
1321 * Invalidate this result and continue visiting dependent results
1322 * with this [Delta]. Keep the dependencies of this result.
1323 */
1324 INVALIDATE_KEEP_DEPENDENCIES,
1325
1326 /**
1055 * Invalidate this result and stop using this [Delta], so unconditionally 1327 * Invalidate this result and stop using this [Delta], so unconditionally
1056 * invalidate all the dependent results. 1328 * invalidate all the dependent results.
1057 */ 1329 */
1058 INVALIDATE_NO_DELTA, 1330 INVALIDATE_NO_DELTA,
1059 1331
1060 /** 1332 /**
1061 * Keep this result and continue validating dependent results 1333 * Keep this result and continue validating dependent results
1062 * with this [Delta]. 1334 * with this [Delta].
1063 */ 1335 */
1064 KEEP_CONTINUE, 1336 KEEP_CONTINUE,
1065 1337
1066 /** 1338 /**
1067 * Keep this result and stop visiting results that depend on this one. 1339 * Keep this result and stop visiting results that depend on this one.
1068 */ 1340 */
1069 STOP 1341 STOP
1070 } 1342 }
1071 1343
1072 /** 1344 /**
1073 * [InvalidatedResult] describes an invalidated result. 1345 * [InvalidatedResult] describes an invalidated result.
1074 */ 1346 */
1075 class InvalidatedResult { 1347 class InvalidatedResult<V> {
1076 /** 1348 /**
1077 * The target in which the result was invalidated. 1349 * The target in which the result was invalidated.
1078 */ 1350 */
1079 final CacheEntry entry; 1351 final CacheEntry entry;
1080 1352
1081 /** 1353 /**
1082 * The descriptor of the result which was invalidated. 1354 * The descriptor of the result which was invalidated.
1083 */ 1355 */
1084 final ResultDescriptor descriptor; 1356 final ResultDescriptor<V> descriptor;
1085 1357
1086 /** 1358 /**
1087 * The value of the result which was invalidated. 1359 * The value of the result before it was invalidated, may be the default
1360 * value if the result was flushed.
1088 */ 1361 */
1089 final Object value; 1362 final V value;
1090 1363
1091 InvalidatedResult(this.entry, this.descriptor, this.value); 1364 InvalidatedResult(this.entry, this.descriptor, this.value);
1092 1365
1093 @override 1366 @override
1094 String toString() => '$descriptor of ${entry.target}'; 1367 String toString() => '$descriptor of ${entry.target}';
1095 } 1368 }
1096 1369
1097 /** 1370 /**
1371 * A cache partition that contains all of the targets in a single package.
1372 */
1373 class PackageCachePartition extends CachePartition {
1374 /**
1375 * The root of the directory representing the package.
1376 */
1377 final Folder packageRoot;
1378
1379 /**
1380 * Initialize a newly created cache partition, belonging to the given
1381 * [context].
1382 */
1383 PackageCachePartition(InternalAnalysisContext context, this.packageRoot)
1384 : super(context);
1385
1386 @override
1387 bool isResponsibleFor(AnalysisTarget target) {
1388 Source source = target.source;
1389 return source != null && packageRoot.contains(source.fullName);
1390 }
1391 }
1392
1393 /**
1098 * A Stream-like interface, which broadcasts events synchronously. 1394 * A Stream-like interface, which broadcasts events synchronously.
1099 * If a second event is fired while delivering a first event, then the second 1395 * If a second event is fired while delivering a first event, then the second
1100 * event will be delivered first, and then delivering of the first will be 1396 * event will be delivered first, and then delivering of the first will be
1101 * continued. 1397 * continued.
1102 */ 1398 */
1103 class ReentrantSynchronousStream<T> { 1399 class ReentrantSynchronousStream<T> {
1104 final List<Function> listeners = <Function>[]; 1400 final List<Function> listeners = <Function>[];
1105 1401
1106 /** 1402 /**
1107 * Send the given [event] to the stream. 1403 * Send the given [event] to the stream.
1108 */ 1404 */
1109 void add(T event) { 1405 void add(T event) {
1110 List<Function> listeners = this.listeners.toList(); 1406 List<Function> listeners = this.listeners.toList();
1111 for (Function listener in listeners) { 1407 for (Function listener in listeners) {
1112 listener(event); 1408 listener(event);
1113 } 1409 }
1114 } 1410 }
1115 1411
1116 /** 1412 /**
1117 * Listen for the events in this stream. 1413 * Listen for the events in this stream.
1118 * Note that if the [listener] fires a new event, then the [listener] will be 1414 * Note that if the [listener] fires a new event, then the [listener] will be
1119 * invoked again before returning from the [add] invocation. 1415 * invoked again before returning from the [add] invocation.
1120 */ 1416 */
1121 void listen(void listener(T event)) { 1417 ReentrantSynchronousStreamSubscription<T> listen(void listener(T event)) {
1122 listeners.add(listener); 1418 listeners.add(listener);
1419 return new ReentrantSynchronousStreamSubscription<T>(this, listener);
1123 } 1420 }
1124 } 1421 }
1125 1422
1423 /**
1424 * A subscription on events from a [ReentrantSynchronousStream].
1425 */
1426 class ReentrantSynchronousStreamSubscription<T> {
1427 final ReentrantSynchronousStream<T> _stream;
1428 final Function _listener;
1429
1430 ReentrantSynchronousStreamSubscription(this._stream, this._listener);
1431
1432 /**
1433 * Cancels this subscription.
1434 * It will no longer receive events.
1435 */
1436 void cancel() {
1437 _stream.listeners.remove(_listener);
1438 }
1439 }
1440
1126 /** 1441 /**
1127 * The data about a single analysis result that is stored in a [CacheEntry]. 1442 * The data about a single analysis result that is stored in a [CacheEntry].
1128 */ 1443 */
1129 // TODO(brianwilkerson) Consider making this a generic class so that the value 1444 // TODO(brianwilkerson) Consider making this a generic class so that the value
1130 // can be typed. 1445 // can be typed.
1131 class ResultData { 1446 class ResultData {
1132 /** 1447 /**
1133 * The [ResultDescriptor] this result is for. 1448 * The [ResultDescriptor] this result is for.
1134 */ 1449 */
1135 final ResultDescriptor descriptor; 1450 final ResultDescriptor descriptor;
1136 1451
1137 /** 1452 /**
1138 * The state of the cached value. 1453 * The state of the cached value.
1139 */ 1454 */
1140 CacheState state; 1455 CacheState state;
1141 1456
1142 /** 1457 /**
1143 * The value being cached, or the default value for the result if there is no 1458 * The value being cached, or the default value for the result if there is no
1144 * value (for example, when the [state] is [CacheState.INVALID]). 1459 * value (for example, when the [state] is [CacheState.INVALID]).
1145 */ 1460 */
1146 Object value; 1461 Object value;
1147 1462
1148 /** 1463 /**
1149 * The identifier of the invalidation process that most recently checked 1464 * The identifier of the most recent visiting process. We use it to visit
1150 * this value. If it is the same as the current invalidation identifier, 1465 * every result only once.
1151 * then there is no reason to check it (and its subtree again).
1152 */ 1466 */
1153 int invalidateId = -1; 1467 int visitId = -1;
1154 1468
1155 /** 1469 /**
1156 * A list of the results on which this result depends. 1470 * A list of the results on which this result depends.
1157 */ 1471 */
1158 List<TargetedResult> dependedOnResults = <TargetedResult>[]; 1472 List<TargetedResult> dependedOnResults = <TargetedResult>[];
1159 1473
1160 /** 1474 /**
1161 * A list of the results that depend on this result. 1475 * A list of the results that depend on this result.
1162 */ 1476 */
1163 Set<TargetedResult> dependentResults = new Set<TargetedResult>(); 1477 Set<TargetedResult> dependentResults = new Set<TargetedResult>();
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 void resultAccessed(TargetedResult result) {} 1540 void resultAccessed(TargetedResult result) {}
1227 1541
1228 @override 1542 @override
1229 List<TargetedResult> resultStored(TargetedResult newResult, newValue) { 1543 List<TargetedResult> resultStored(TargetedResult newResult, newValue) {
1230 return TargetedResult.EMPTY_LIST; 1544 return TargetedResult.EMPTY_LIST;
1231 } 1545 }
1232 1546
1233 @override 1547 @override
1234 void targetRemoved(AnalysisTarget target) {} 1548 void targetRemoved(AnalysisTarget target) {}
1235 } 1549 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/context/builder.dart ('k') | packages/analyzer/lib/src/context/context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698