| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |