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:collection'; | 7 import 'dart:collection'; |
8 | 8 |
9 import 'package:analyzer/src/generated/ast.dart'; | |
10 import 'package:analyzer/src/generated/engine.dart' | 9 import 'package:analyzer/src/generated/engine.dart' |
11 show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority; | 10 show AnalysisEngine, CacheState, InternalAnalysisContext, RetentionPriority; |
12 import 'package:analyzer/src/generated/html.dart'; | |
13 import 'package:analyzer/src/generated/java_engine.dart'; | 11 import 'package:analyzer/src/generated/java_engine.dart'; |
14 import 'package:analyzer/src/generated/source.dart'; | 12 import 'package:analyzer/src/generated/source.dart'; |
15 import 'package:analyzer/src/generated/utilities_collection.dart'; | 13 import 'package:analyzer/src/generated/utilities_collection.dart'; |
16 import 'package:analyzer/src/generated/utilities_general.dart'; | 14 import 'package:analyzer/src/generated/utilities_general.dart'; |
17 import 'package:analyzer/task/model.dart'; | 15 import 'package:analyzer/task/model.dart'; |
18 | 16 |
19 /** | 17 /** |
| 18 * Return `true` if the given [target] is a priority one. |
| 19 */ |
| 20 typedef bool IsPriorityAnalysisTarget(AnalysisTarget target); |
| 21 |
| 22 /** |
20 * An LRU cache of results produced by analysis. | 23 * An LRU cache of results produced by analysis. |
21 */ | 24 */ |
22 class AnalysisCache { | 25 class AnalysisCache { |
23 /** | 26 /** |
24 * A flag used to control whether trace information should be produced when | 27 * A flag used to control whether trace information should be produced when |
25 * the content of the cache is modified. | 28 * the content of the cache is modified. |
26 */ | 29 */ |
27 static bool _TRACE_CHANGES = false; | 30 static bool _TRACE_CHANGES = false; |
28 | 31 |
29 /** | 32 /** |
30 * An array containing the partitions of which this cache is comprised. | 33 * An array containing the partitions of which this cache is comprised. |
31 */ | 34 */ |
32 final List<CachePartition> _partitions; | 35 final List<CachePartition> _partitions; |
33 | 36 |
34 /** | 37 /** |
35 * Initialize a newly created cache to have the given [partitions]. The | 38 * Initialize a newly created cache to have the given [partitions]. The |
36 * partitions will be searched in the order in which they appear in the array, | 39 * partitions will be searched in the order in which they appear in the array, |
37 * so the most specific partition (usually an [SdkCachePartition]) should be | 40 * so the most specific partition (usually an [SdkCachePartition]) should be |
38 * first and the most general (usually a [UniversalCachePartition]) last. | 41 * first and the most general (usually a [UniversalCachePartition]) last. |
39 */ | 42 */ |
40 AnalysisCache(this._partitions); | 43 AnalysisCache(this._partitions) { |
41 | 44 for (CachePartition partition in _partitions) { |
42 /** | 45 partition._cache = this; |
43 * Return the number of entries in this cache that have an AST associated with | 46 } |
44 * them. | 47 } |
45 */ | |
46 int get astSize => _partitions[_partitions.length - 1].astSize; | |
47 | 48 |
48 // TODO(brianwilkerson) Implement or delete this. | 49 // TODO(brianwilkerson) Implement or delete this. |
49 // /** | 50 // /** |
50 // * Return information about each of the partitions in this cache. | 51 // * Return information about each of the partitions in this cache. |
51 // */ | 52 // */ |
52 // List<AnalysisContextStatistics_PartitionData> get partitionData { | 53 // List<AnalysisContextStatistics_PartitionData> get partitionData { |
53 // int count = _partitions.length; | 54 // int count = _partitions.length; |
54 // List<AnalysisContextStatistics_PartitionData> data = | 55 // List<AnalysisContextStatistics_PartitionData> data = |
55 // new List<AnalysisContextStatistics_PartitionData>(count); | 56 // new List<AnalysisContextStatistics_PartitionData>(count); |
56 // for (int i = 0; i < count; i++) { | 57 // for (int i = 0; i < count; i++) { |
57 // CachePartition partition = _partitions[i]; | 58 // CachePartition partition = _partitions[i]; |
58 // data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl( | 59 // data[i] = new AnalysisContextStatisticsImpl_PartitionDataImpl( |
59 // partition.astSize, | 60 // partition.astSize, |
60 // partition.map.length); | 61 // partition.map.length); |
61 // } | 62 // } |
62 // return data; | 63 // return data; |
63 // } | 64 // } |
64 | 65 |
65 /** | 66 /** |
66 * Record that the AST associated with the given [target] was just read from | |
67 * the cache. | |
68 */ | |
69 void accessedAst(AnalysisTarget target) { | |
70 // TODO(brianwilkerson) Extract this logic to a helper method (here and | |
71 // elsewhere) | |
72 int count = _partitions.length; | |
73 for (int i = 0; i < count; i++) { | |
74 if (_partitions[i].contains(target)) { | |
75 _partitions[i].accessedAst(target); | |
76 return; | |
77 } | |
78 } | |
79 } | |
80 | |
81 /** | |
82 * Return the entry associated with the given [target]. | 67 * Return the entry associated with the given [target]. |
83 */ | 68 */ |
84 CacheEntry get(AnalysisTarget target) { | 69 CacheEntry get(AnalysisTarget target) { |
85 int count = _partitions.length; | 70 int count = _partitions.length; |
86 for (int i = 0; i < count; i++) { | 71 for (int i = 0; i < count; i++) { |
87 if (_partitions[i].contains(target)) { | 72 if (_partitions[i].contains(target)) { |
88 return _partitions[i].get(target); | 73 return _partitions[i].get(target); |
89 } | 74 } |
90 } | 75 } |
91 // | 76 // |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 for (int i = 0; i < count; i++) { | 113 for (int i = 0; i < count; i++) { |
129 maps[i] = _partitions[i].map; | 114 maps[i] = _partitions[i].map; |
130 } | 115 } |
131 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); | 116 return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps); |
132 } | 117 } |
133 | 118 |
134 /** | 119 /** |
135 * Associate the given [entry] with the given [target]. | 120 * Associate the given [entry] with the given [target]. |
136 */ | 121 */ |
137 void put(AnalysisTarget target, CacheEntry entry) { | 122 void put(AnalysisTarget target, CacheEntry entry) { |
138 entry._cache = this; | |
139 entry._target = target; | |
140 entry.fixExceptionState(); | 123 entry.fixExceptionState(); |
141 int count = _partitions.length; | 124 int count = _partitions.length; |
142 for (int i = 0; i < count; i++) { | 125 for (int i = 0; i < count; i++) { |
143 if (_partitions[i].contains(target)) { | 126 if (_partitions[i].contains(target)) { |
144 if (_TRACE_CHANGES) { | 127 if (_TRACE_CHANGES) { |
145 CacheEntry oldEntry = _partitions[i].get(target); | 128 CacheEntry oldEntry = _partitions[i].get(target); |
146 if (oldEntry == null) { | 129 if (oldEntry == null) { |
147 AnalysisEngine.instance.logger | 130 AnalysisEngine.instance.logger |
148 .logInformation('Added a cache entry for $target.'); | 131 .logInformation('Added a cache entry for $target.'); |
149 } else { | 132 } else { |
(...skipping 21 matching lines...) Expand all Loading... |
171 AnalysisEngine.instance.logger | 154 AnalysisEngine.instance.logger |
172 .logInformation('Removed the cache entry for $target.'); | 155 .logInformation('Removed the cache entry for $target.'); |
173 } | 156 } |
174 _partitions[i].remove(target); | 157 _partitions[i].remove(target); |
175 return; | 158 return; |
176 } | 159 } |
177 } | 160 } |
178 } | 161 } |
179 | 162 |
180 /** | 163 /** |
181 * Record that the AST associated with the given [target] was just removed | |
182 * from the cache. | |
183 */ | |
184 void removedAst(AnalysisTarget target) { | |
185 int count = _partitions.length; | |
186 for (int i = 0; i < count; i++) { | |
187 if (_partitions[i].contains(target)) { | |
188 _partitions[i].removedAst(target); | |
189 return; | |
190 } | |
191 } | |
192 } | |
193 | |
194 /** | |
195 * Return the number of targets that are mapped to cache entries. | 164 * Return the number of targets that are mapped to cache entries. |
196 */ | 165 */ |
197 int size() { | 166 int size() { |
198 int size = 0; | 167 int size = 0; |
199 int count = _partitions.length; | 168 int count = _partitions.length; |
200 for (int i = 0; i < count; i++) { | 169 for (int i = 0; i < count; i++) { |
201 size += _partitions[i].size(); | 170 size += _partitions[i].size(); |
202 } | 171 } |
203 return size; | 172 return size; |
204 } | 173 } |
205 | 174 |
206 /** | |
207 * Record that the AST associated with the given [target] was just stored to | |
208 * the cache. | |
209 */ | |
210 void storedAst(AnalysisTarget target) { | |
211 int count = _partitions.length; | |
212 for (int i = 0; i < count; i++) { | |
213 if (_partitions[i].contains(target)) { | |
214 _partitions[i].storedAst(target); | |
215 return; | |
216 } | |
217 } | |
218 } | |
219 | |
220 ResultData _getDataFor(TargetedResult result) { | 175 ResultData _getDataFor(TargetedResult result) { |
221 AnalysisTarget target = result.target; | 176 AnalysisTarget target = result.target; |
222 int count = _partitions.length; | 177 int count = _partitions.length; |
223 for (int i = 0; i < count; i++) { | 178 for (int i = 0; i < count; i++) { |
224 if (_partitions[i].contains(target)) { | 179 if (_partitions[i].contains(target)) { |
225 CacheEntry entry = _partitions[i].get(target); | 180 CacheEntry entry = _partitions[i].get(target); |
226 return entry._getResultData(result.result); | 181 return entry._getResultData(result.result); |
227 } | 182 } |
228 } | 183 } |
229 return null; | 184 return null; |
230 } | 185 } |
231 } | 186 } |
232 | 187 |
233 /** | 188 /** |
234 * The information cached by an analysis context about an individual target. | 189 * The information cached by an analysis context about an individual target. |
235 */ | 190 */ |
236 class CacheEntry { | 191 class CacheEntry { |
237 /** | 192 /** |
238 * The index of the flag indicating whether the source was explicitly added to | 193 * The index of the flag indicating whether the source was explicitly added to |
239 * the context or whether the source was implicitly added because it was | 194 * the context or whether the source was implicitly added because it was |
240 * referenced by another source. | 195 * referenced by another source. |
241 */ | 196 */ |
242 static int _EXPLICITLY_ADDED_FLAG = 0; | 197 static int _EXPLICITLY_ADDED_FLAG = 0; |
243 | 198 |
244 /** | 199 /** |
245 * The cache that contains this entry. | 200 * The partition that is responsible for this entry. |
246 */ | 201 */ |
247 AnalysisCache _cache; | 202 CachePartition _partition; |
248 | 203 |
249 /** | 204 /** |
250 * The target this entry is about. | 205 * The target this entry is about. |
251 */ | 206 */ |
252 AnalysisTarget _target; | 207 AnalysisTarget _target; |
253 | 208 |
254 /** | 209 /** |
255 * The most recent time at which the state of the target matched the state | 210 * The most recent time at which the state of the target matched the state |
256 * represented by this entry. | 211 * represented by this entry. |
257 */ | 212 */ |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 | 244 |
290 /** | 245 /** |
291 * Set whether the source was explicitly added to the context to match the | 246 * Set whether the source was explicitly added to the context to match the |
292 * [explicitlyAdded] flag. | 247 * [explicitlyAdded] flag. |
293 */ | 248 */ |
294 void set explicitlyAdded(bool explicitlyAdded) { | 249 void set explicitlyAdded(bool explicitlyAdded) { |
295 _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded); | 250 _setFlag(_EXPLICITLY_ADDED_FLAG, explicitlyAdded); |
296 } | 251 } |
297 | 252 |
298 /** | 253 /** |
299 * Return `true` if this entry contains at least one result whose value is an | |
300 * AST structure. | |
301 */ | |
302 bool get hasAstStructure { | |
303 for (ResultData data in _resultMap.values) { | |
304 if (data.value is AstNode || data.value is XmlNode) { | |
305 return true; | |
306 } | |
307 } | |
308 return false; | |
309 } | |
310 | |
311 /** | |
312 * Fix the state of the [exception] to match the current state of the entry. | 254 * Fix the state of the [exception] to match the current state of the entry. |
313 */ | 255 */ |
314 void fixExceptionState() { | 256 void fixExceptionState() { |
315 if (!hasErrorState()) { | 257 if (!hasErrorState()) { |
316 _exception = null; | 258 _exception = null; |
317 } | 259 } |
318 } | 260 } |
319 | 261 |
320 /** | 262 /** |
321 * Mark any AST structures associated with this cache entry as being flushed. | |
322 */ | |
323 void flushAstStructures() { | |
324 _resultMap.forEach((ResultDescriptor descriptor, ResultData data) { | |
325 if (data.value is AstNode || data.value is XmlNode) { | |
326 _validateStateChange(descriptor, CacheState.FLUSHED); | |
327 data.state = CacheState.FLUSHED; | |
328 data.value = descriptor.defaultValue; | |
329 } | |
330 }); | |
331 } | |
332 | |
333 /** | |
334 * Return the memento of the result represented by the given [descriptor]. | 263 * Return the memento of the result represented by the given [descriptor]. |
335 */ | 264 */ |
336 Object getMemento(ResultDescriptor descriptor) { | 265 Object getMemento(ResultDescriptor descriptor) { |
337 ResultData data = _resultMap[descriptor]; | 266 ResultData data = _resultMap[descriptor]; |
338 if (data == null) { | 267 if (data == null) { |
339 return null; | 268 return null; |
340 } | 269 } |
341 return data.memento; | 270 return data.memento; |
342 } | 271 } |
343 | 272 |
(...skipping 10 matching lines...) Expand all Loading... |
354 | 283 |
355 /** | 284 /** |
356 * Return the value of the result represented by the given [descriptor], or | 285 * Return the value of the result represented by the given [descriptor], or |
357 * the default value for the result if this entry does not have a valid value. | 286 * the default value for the result if this entry does not have a valid value. |
358 */ | 287 */ |
359 /*<V>*/ dynamic /*V*/ getValue(ResultDescriptor /*<V>*/ descriptor) { | 288 /*<V>*/ dynamic /*V*/ getValue(ResultDescriptor /*<V>*/ descriptor) { |
360 ResultData data = _resultMap[descriptor]; | 289 ResultData data = _resultMap[descriptor]; |
361 if (data == null) { | 290 if (data == null) { |
362 return descriptor.defaultValue; | 291 return descriptor.defaultValue; |
363 } | 292 } |
| 293 if (_partition != null) { |
| 294 _partition.resultAccessed(_target, descriptor); |
| 295 } |
364 return data.value; | 296 return data.value; |
365 } | 297 } |
366 | 298 |
367 /** | 299 /** |
368 * Return `true` if the state of any data value is [CacheState.ERROR]. | 300 * Return `true` if the state of any data value is [CacheState.ERROR]. |
369 */ | 301 */ |
370 bool hasErrorState() { | 302 bool hasErrorState() { |
371 for (ResultData data in _resultMap.values) { | 303 for (ResultData data in _resultMap.values) { |
372 if (data.state == CacheState.ERROR) { | 304 if (data.state == CacheState.ERROR) { |
373 return true; | 305 return true; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 if (descriptors == null || descriptors.isEmpty) { | 340 if (descriptors == null || descriptors.isEmpty) { |
409 throw new ArgumentError('at least one descriptor is expected'); | 341 throw new ArgumentError('at least one descriptor is expected'); |
410 } | 342 } |
411 if (exception == null) { | 343 if (exception == null) { |
412 throw new ArgumentError('an exception is expected'); | 344 throw new ArgumentError('an exception is expected'); |
413 } | 345 } |
414 this._exception = exception; | 346 this._exception = exception; |
415 for (ResultDescriptor descriptor in descriptors) { | 347 for (ResultDescriptor descriptor in descriptors) { |
416 ResultData data = _getResultData(descriptor); | 348 ResultData data = _getResultData(descriptor); |
417 TargetedResult thisResult = new TargetedResult(_target, descriptor); | 349 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
418 data.invalidate(_cache, thisResult, CacheState.ERROR); | 350 data.invalidate(_partition, thisResult, CacheState.ERROR); |
419 } | 351 } |
420 } | 352 } |
421 | 353 |
422 /** | 354 /** |
423 * Set the state of the result represented by the given [descriptor] to the | 355 * Set the state of the result represented by the given [descriptor] to the |
424 * given [state]. | 356 * given [state]. |
425 */ | 357 */ |
426 void setState(ResultDescriptor descriptor, CacheState state) { | 358 void setState(ResultDescriptor descriptor, CacheState state) { |
427 if (state == CacheState.ERROR) { | 359 if (state == CacheState.ERROR) { |
428 throw new ArgumentError('use setErrorState() to set the state to ERROR'); | 360 throw new ArgumentError('use setErrorState() to set the state to ERROR'); |
429 } | 361 } |
430 if (state == CacheState.VALID) { | 362 if (state == CacheState.VALID) { |
431 throw new ArgumentError('use setValue() to set the state to VALID'); | 363 throw new ArgumentError('use setValue() to set the state to VALID'); |
432 } | 364 } |
433 _validateStateChange(descriptor, state); | 365 _validateStateChange(descriptor, state); |
434 if (state == CacheState.INVALID) { | 366 if (state == CacheState.INVALID) { |
435 ResultData data = _resultMap[descriptor]; | 367 ResultData data = _resultMap[descriptor]; |
436 if (data != null) { | 368 if (data != null) { |
437 TargetedResult thisResult = new TargetedResult(_target, descriptor); | 369 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
438 data.invalidate(_cache, thisResult, CacheState.INVALID); | 370 data.invalidate(_partition, thisResult, CacheState.INVALID); |
439 } | 371 } |
440 } else { | 372 } else { |
441 ResultData data = _getResultData(descriptor); | 373 ResultData data = _getResultData(descriptor); |
442 data.state = state; | 374 data.state = state; |
443 if (state != CacheState.IN_PROCESS) { | 375 if (state != CacheState.IN_PROCESS) { |
444 // | 376 // |
445 // If the state is in-process, we can leave the current value in the | 377 // If the state is in-process, we can leave the current value in the |
446 // cache for any 'get' methods to access. | 378 // cache for any 'get' methods to access. |
447 // | 379 // |
448 data.value = descriptor.defaultValue; | 380 data.value = descriptor.defaultValue; |
449 } | 381 } |
450 } | 382 } |
451 } | 383 } |
452 | 384 |
453 /** | 385 /** |
454 * Set the value of the result represented by the given [descriptor] to the | 386 * Set the value of the result represented by the given [descriptor] to the |
455 * given [value]. The optional [memento] may help to recompute [value] more | 387 * given [value]. The optional [memento] may help to recompute [value] more |
456 * efficiently after invalidation. | 388 * efficiently after invalidation. |
457 */ | 389 */ |
458 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ | 390 /*<V>*/ void setValue(ResultDescriptor /*<V>*/ descriptor, dynamic /*V*/ |
459 value, List<TargetedResult> dependedOn, Object memento) { | 391 value, List<TargetedResult> dependedOn, Object memento) { |
460 _validateStateChange(descriptor, CacheState.VALID); | 392 _validateStateChange(descriptor, CacheState.VALID); |
| 393 TargetedResult thisResult = new TargetedResult(_target, descriptor); |
| 394 if (_partition != null) { |
| 395 _partition.resultStored(thisResult, value); |
| 396 } |
461 ResultData data = _getResultData(descriptor); | 397 ResultData data = _getResultData(descriptor); |
462 { | 398 data.invalidate(_partition, thisResult, CacheState.INVALID); |
463 TargetedResult thisResult = new TargetedResult(_target, descriptor); | 399 data.setDependedOnResults(_partition, thisResult, dependedOn); |
464 data.invalidate(_cache, thisResult, CacheState.INVALID); | |
465 data.setDependedOnResults(_cache, thisResult, dependedOn); | |
466 } | |
467 data.state = CacheState.VALID; | 400 data.state = CacheState.VALID; |
468 data.value = value == null ? descriptor.defaultValue : value; | 401 data.value = value == null ? descriptor.defaultValue : value; |
469 data.memento = memento; | 402 data.memento = memento; |
470 } | 403 } |
471 | 404 |
472 @override | 405 @override |
473 String toString() { | 406 String toString() { |
474 StringBuffer buffer = new StringBuffer(); | 407 StringBuffer buffer = new StringBuffer(); |
475 _writeOn(buffer); | 408 _writeOn(buffer); |
476 return buffer.toString(); | 409 return buffer.toString(); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 ResultData data = _resultMap[result]; | 466 ResultData data = _resultMap[result]; |
534 buffer.write('; '); | 467 buffer.write('; '); |
535 buffer.write(result.toString()); | 468 buffer.write(result.toString()); |
536 buffer.write(' = '); | 469 buffer.write(' = '); |
537 buffer.write(data.state); | 470 buffer.write(data.state); |
538 } | 471 } |
539 } | 472 } |
540 } | 473 } |
541 | 474 |
542 /** | 475 /** |
| 476 * An object that controls flushing of analysis results from the cache. |
| 477 */ |
| 478 class CacheFlushManager<T> { |
| 479 final IsPriorityAnalysisTarget isPriorityAnalysisTarget; |
| 480 final ResultCachingPolicy<T> policy; |
| 481 final int maxActiveSize; |
| 482 final int maxIdleSize; |
| 483 |
| 484 /** |
| 485 * A map of the stored [TargetedResult] to their sizes. |
| 486 */ |
| 487 final HashMap<TargetedResult, int> resultSizeMap = |
| 488 new HashMap<TargetedResult, int>(); |
| 489 |
| 490 /** |
| 491 * A linked set containing the most recently accessed results with the most |
| 492 * recently used at the end of the list. When more results are added than the |
| 493 * maximum size allowed then the least recently used results will be flushed |
| 494 * from the cache. |
| 495 */ |
| 496 final LinkedHashSet<TargetedResult> recentlyUsed = |
| 497 new LinkedHashSet<TargetedResult>(); |
| 498 |
| 499 /** |
| 500 * The current size of stored results. |
| 501 */ |
| 502 int currentSize = 0; |
| 503 |
| 504 /** |
| 505 * The current maximum cache size. |
| 506 */ |
| 507 int maxSize; |
| 508 |
| 509 CacheFlushManager( |
| 510 ResultCachingPolicy<T> policy, this.isPriorityAnalysisTarget) |
| 511 : policy = policy, |
| 512 maxActiveSize = policy.maxActiveSize, |
| 513 maxIdleSize = policy.maxIdleSize, |
| 514 maxSize = policy.maxIdleSize; |
| 515 |
| 516 /** |
| 517 * If [currentSize] is already less than [maxSize], returns an empty list. |
| 518 * Otherwise returns [TargetedResult]s to flush from the cache to make |
| 519 * [currentSize] less or equal to [maxSize]. |
| 520 * |
| 521 * Results for priority files are never flushed, so this method might leave |
| 522 * [currentSize] greater than [maxSize]. |
| 523 */ |
| 524 List<TargetedResult> flushToSize() { |
| 525 // If still under the cap, done. |
| 526 if (maxSize == -1 || currentSize <= maxSize) { |
| 527 return TargetedResult.EMPTY_LIST; |
| 528 } |
| 529 // Flush results until we are under the cap. |
| 530 List<TargetedResult> resultsToFlush = <TargetedResult>[]; |
| 531 for (TargetedResult result in recentlyUsed) { |
| 532 if (isPriorityAnalysisTarget(result.target)) { |
| 533 continue; |
| 534 } |
| 535 resultsToFlush.add(result); |
| 536 int size = resultSizeMap.remove(result); |
| 537 assert(size != null); |
| 538 currentSize -= size; |
| 539 if (currentSize <= maxSize) { |
| 540 break; |
| 541 } |
| 542 } |
| 543 recentlyUsed.removeAll(resultsToFlush); |
| 544 return resultsToFlush; |
| 545 } |
| 546 |
| 547 /** |
| 548 * Notifies this manager that the corresponding analysis context is active. |
| 549 */ |
| 550 void madeActive() { |
| 551 maxSize = maxActiveSize; |
| 552 } |
| 553 |
| 554 /** |
| 555 * Notifies this manager that the corresponding analysis context is idle. |
| 556 * Returns [TargetedResult]s that should be flushed from the cache. |
| 557 */ |
| 558 List<TargetedResult> madeIdle() { |
| 559 maxSize = maxIdleSize; |
| 560 return flushToSize(); |
| 561 } |
| 562 |
| 563 /** |
| 564 * Records that the given [result] was just read from the cache. |
| 565 */ |
| 566 void resultAccessed(TargetedResult result) { |
| 567 if (recentlyUsed.remove(result)) { |
| 568 recentlyUsed.add(result); |
| 569 } |
| 570 } |
| 571 |
| 572 /** |
| 573 * Records that the given [newResult] and [newValue] were stored to the cache. |
| 574 * Returns [TargetedResult]s that should be flushed from the cache. |
| 575 */ |
| 576 List<TargetedResult> resultStored(TargetedResult newResult, T newValue) { |
| 577 if (!recentlyUsed.remove(newResult)) { |
| 578 int size = policy.measure(newValue); |
| 579 resultSizeMap[newResult] = size; |
| 580 currentSize += size; |
| 581 } |
| 582 recentlyUsed.add(newResult); |
| 583 return flushToSize(); |
| 584 } |
| 585 |
| 586 /** |
| 587 * Records that the given [target] was just removed from to the cache. |
| 588 */ |
| 589 void targetRemoved(AnalysisTarget target) { |
| 590 List<TargetedResult> resultsToRemove = <TargetedResult>[]; |
| 591 for (TargetedResult result in recentlyUsed) { |
| 592 if (result.target == target) { |
| 593 resultsToRemove.add(result); |
| 594 int size = resultSizeMap.remove(result); |
| 595 assert(size != null); |
| 596 currentSize -= size; |
| 597 } |
| 598 } |
| 599 recentlyUsed.removeAll(resultsToRemove); |
| 600 } |
| 601 } |
| 602 |
| 603 /** |
543 * A single partition in an LRU cache of information related to analysis. | 604 * A single partition in an LRU cache of information related to analysis. |
544 */ | 605 */ |
545 abstract class CachePartition { | 606 abstract class CachePartition { |
546 /** | 607 /** |
| 608 * The [AnalysisCache] that owns this partition. |
| 609 * |
| 610 * TODO(scheglov) It seems wrong. Partitions may be shared between caches. |
| 611 * But we need a way to go from every "enclosing" partition into "enclosed" |
| 612 * ones. |
| 613 */ |
| 614 AnalysisCache _cache; |
| 615 |
| 616 /** |
547 * The context that owns this partition. Multiple contexts can reference a | 617 * The context that owns this partition. Multiple contexts can reference a |
548 * partition, but only one context can own it. | 618 * partition, but only one context can own it. |
549 */ | 619 */ |
550 final InternalAnalysisContext context; | 620 final InternalAnalysisContext context; |
551 | 621 |
552 /** | 622 /** |
553 * The maximum number of sources for which AST structures should be kept in | 623 * A table mapping caching policies to the cache flush managers. |
554 * the cache. | |
555 */ | 624 */ |
556 int _maxCacheSize = 0; | 625 final HashMap<ResultCachingPolicy, CacheFlushManager> _flushManagerMap = |
557 | 626 new HashMap<ResultCachingPolicy, CacheFlushManager>(); |
558 /** | |
559 * The policy used to determine which results to remove from the cache. | |
560 */ | |
561 final CacheRetentionPolicy _retentionPolicy; | |
562 | 627 |
563 /** | 628 /** |
564 * A table mapping the targets belonging to this partition to the information | 629 * A table mapping the targets belonging to this partition to the information |
565 * known about those targets. | 630 * known about those targets. |
566 */ | 631 */ |
567 HashMap<AnalysisTarget, CacheEntry> _targetMap = | 632 HashMap<AnalysisTarget, CacheEntry> _targetMap = |
568 new HashMap<AnalysisTarget, CacheEntry>(); | 633 new HashMap<AnalysisTarget, CacheEntry>(); |
569 | 634 |
570 /** | 635 /** |
571 * A list containing the most recently accessed targets with the most recently | 636 * Initialize a newly created cache partition, belonging to the given |
572 * used at the end of the list. When more targets are added than the maximum | 637 * [context]. |
573 * allowed then the least recently used target will be removed and will have | |
574 * it's cached AST structure flushed. | |
575 */ | 638 */ |
576 List<AnalysisTarget> _recentlyUsed = <AnalysisTarget>[]; | 639 CachePartition(this.context); |
577 | |
578 /** | |
579 * Initialize a newly created cache partition, belonging to the given | |
580 * [context]. The partition will maintain at most [_maxCacheSize] AST | |
581 * structures in the cache, using the [_retentionPolicy] to determine which | |
582 * AST structures to flush. | |
583 */ | |
584 CachePartition(this.context, this._maxCacheSize, this._retentionPolicy); | |
585 | |
586 /** | |
587 * Return the number of entries in this partition that have an AST associated | |
588 * with them. | |
589 */ | |
590 int get astSize { | |
591 int astSize = 0; | |
592 int count = _recentlyUsed.length; | |
593 for (int i = 0; i < count; i++) { | |
594 AnalysisTarget target = _recentlyUsed[i]; | |
595 CacheEntry entry = _targetMap[target]; | |
596 if (entry.hasAstStructure) { | |
597 astSize++; | |
598 } | |
599 } | |
600 return astSize; | |
601 } | |
602 | 640 |
603 /** | 641 /** |
604 * Return a table mapping the targets known to the context to the information | 642 * Return a table mapping the targets known to the context to the information |
605 * known about the target. | 643 * known about the target. |
606 * | 644 * |
607 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and | 645 * <b>Note:</b> This method is only visible for use by [AnalysisCache] and |
608 * should not be used for any other purpose. | 646 * should not be used for any other purpose. |
609 */ | 647 */ |
610 Map<AnalysisTarget, CacheEntry> get map => _targetMap; | 648 Map<AnalysisTarget, CacheEntry> get map => _targetMap; |
611 | 649 |
612 /** | 650 /** |
613 * Return the maximum size of the cache. | |
614 */ | |
615 int get maxCacheSize => _maxCacheSize; | |
616 | |
617 /** | |
618 * Set the maximum size of the cache to the given [size]. | |
619 */ | |
620 void set maxCacheSize(int size) { | |
621 _maxCacheSize = size; | |
622 while (_recentlyUsed.length > _maxCacheSize) { | |
623 if (!_flushAstFromCache()) { | |
624 break; | |
625 } | |
626 } | |
627 } | |
628 | |
629 /** | |
630 * Record that the AST associated with the given [target] was just read from | |
631 * the cache. | |
632 */ | |
633 void accessedAst(AnalysisTarget target) { | |
634 if (_recentlyUsed.remove(target)) { | |
635 _recentlyUsed.add(target); | |
636 return; | |
637 } | |
638 while (_recentlyUsed.length >= _maxCacheSize) { | |
639 if (!_flushAstFromCache()) { | |
640 break; | |
641 } | |
642 } | |
643 _recentlyUsed.add(target); | |
644 } | |
645 | |
646 /** | |
647 * Return `true` if the given [target] is contained in this partition. | 651 * Return `true` if the given [target] is contained in this partition. |
648 */ | 652 */ |
649 // TODO(brianwilkerson) Rename this to something more meaningful, such as | 653 // TODO(brianwilkerson) Rename this to something more meaningful, such as |
650 // isResponsibleFor. | 654 // isResponsibleFor. |
651 bool contains(AnalysisTarget target); | 655 bool contains(AnalysisTarget target); |
652 | 656 |
653 /** | 657 /** |
654 * Return the entry associated with the given [target]. | 658 * Return the entry associated with the given [target]. |
655 */ | 659 */ |
656 CacheEntry get(AnalysisTarget target) => _targetMap[target]; | 660 CacheEntry get(AnalysisTarget target) => _targetMap[target]; |
657 | 661 |
658 /** | 662 /** |
659 * Return an iterator returning all of the map entries mapping targets to | 663 * Return an iterator returning all of the map entries mapping targets to |
660 * cache entries. | 664 * cache entries. |
661 */ | 665 */ |
662 MapIterator<AnalysisTarget, CacheEntry> iterator() => | 666 MapIterator<AnalysisTarget, CacheEntry> iterator() => |
663 new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap); | 667 new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap); |
664 | 668 |
665 /** | 669 /** |
666 * Associate the given [entry] with the given [target]. | 670 * Associate the given [entry] with the given [target]. |
667 */ | 671 */ |
668 void put(AnalysisTarget target, CacheEntry entry) { | 672 void put(AnalysisTarget target, CacheEntry entry) { |
| 673 if (entry._partition != null) { |
| 674 throw new StateError( |
| 675 'The entry for $target is already in ${entry._partition}'); |
| 676 } |
| 677 entry._partition = this; |
| 678 entry._target = target; |
669 entry.fixExceptionState(); | 679 entry.fixExceptionState(); |
670 _targetMap[target] = entry; | 680 _targetMap[target] = entry; |
671 } | 681 } |
672 | 682 |
673 /** | 683 /** |
674 * Remove all information related to the given [target] from this cache. | 684 * Remove all information related to the given [target] from this cache. |
675 */ | 685 */ |
676 void remove(AnalysisTarget target) { | 686 void remove(AnalysisTarget target) { |
677 _recentlyUsed.remove(target); | 687 for (CacheFlushManager flushManager in _flushManagerMap.values) { |
| 688 flushManager.targetRemoved(target); |
| 689 } |
678 _targetMap.remove(target); | 690 _targetMap.remove(target); |
679 } | 691 } |
680 | 692 |
681 /** | 693 /** |
682 * Record that the AST associated with the given [target] was just removed | 694 * Records that a value of the result described by the given [descriptor] |
683 * from the cache. | 695 * for the given [target] was just read from the cache. |
684 */ | 696 */ |
685 void removedAst(AnalysisTarget target) { | 697 void resultAccessed(AnalysisTarget target, ResultDescriptor descriptor) { |
686 _recentlyUsed.remove(target); | 698 CacheFlushManager flushManager = _getFlushManager(descriptor); |
| 699 TargetedResult result = new TargetedResult(target, descriptor); |
| 700 flushManager.resultAccessed(result); |
| 701 } |
| 702 |
| 703 /** |
| 704 * Records that the given [result] was just stored into the cache. |
| 705 */ |
| 706 void resultStored(TargetedResult result, Object value) { |
| 707 CacheFlushManager flushManager = _getFlushManager(result.result); |
| 708 List<TargetedResult> resultsToFlush = |
| 709 flushManager.resultStored(result, value); |
| 710 for (TargetedResult result in resultsToFlush) { |
| 711 CacheEntry entry = get(result.target); |
| 712 ResultData data = entry._resultMap[result.result]; |
| 713 data.flush(); |
| 714 } |
687 } | 715 } |
688 | 716 |
689 /** | 717 /** |
690 * Return the number of targets that are mapped to cache entries. | 718 * Return the number of targets that are mapped to cache entries. |
691 */ | 719 */ |
692 int size() => _targetMap.length; | 720 int size() => _targetMap.length; |
693 | 721 |
694 /** | 722 ResultData _getDataFor(TargetedResult result) { |
695 * Record that the AST associated with the given [target] was just stored to | 723 return _cache._getDataFor(result); |
696 * the cache. | |
697 */ | |
698 void storedAst(AnalysisTarget target) { | |
699 if (_recentlyUsed.contains(target)) { | |
700 return; | |
701 } | |
702 while (_recentlyUsed.length >= _maxCacheSize) { | |
703 if (!_flushAstFromCache()) { | |
704 break; | |
705 } | |
706 } | |
707 _recentlyUsed.add(target); | |
708 } | 724 } |
709 | 725 |
710 /** | 726 /** |
711 * Attempt to flush one AST structure from the cache. Return `true` if a | 727 * Return the [CacheFlushManager] for the given [descriptor], not `null`. |
712 * structure was flushed. | |
713 */ | 728 */ |
714 bool _flushAstFromCache() { | 729 CacheFlushManager _getFlushManager(ResultDescriptor descriptor) { |
715 AnalysisTarget removedTarget = _removeAstToFlush(); | 730 ResultCachingPolicy policy = descriptor.cachingPolicy; |
716 if (removedTarget == null) { | 731 return _flushManagerMap.putIfAbsent( |
717 return false; | 732 policy, () => new CacheFlushManager(policy, _isPriorityAnalysisTarget)); |
718 } | |
719 CacheEntry entry = _targetMap[removedTarget]; | |
720 entry.flushAstStructures(); | |
721 return true; | |
722 } | 733 } |
723 | 734 |
724 /** | 735 bool _isPriorityAnalysisTarget(AnalysisTarget target) { |
725 * Remove and return one target from the list of recently used targets whose | 736 return context.priorityTargets.contains(target); |
726 * AST structure can be flushed from the cache, or `null` if none of the | |
727 * targets can be removed. The target that will be returned will be the target | |
728 * that has been unreferenced for the longest period of time but that is not a | |
729 * priority for analysis. | |
730 */ | |
731 AnalysisTarget _removeAstToFlush() { | |
732 int targetToRemove = -1; | |
733 for (int i = 0; i < _recentlyUsed.length; i++) { | |
734 AnalysisTarget target = _recentlyUsed[i]; | |
735 RetentionPriority priority = | |
736 _retentionPolicy.getAstPriority(target, _targetMap[target]); | |
737 if (priority == RetentionPriority.LOW) { | |
738 return _recentlyUsed.removeAt(i); | |
739 } else if (priority == RetentionPriority.MEDIUM && targetToRemove < 0) { | |
740 targetToRemove = i; | |
741 } | |
742 } | |
743 if (targetToRemove < 0) { | |
744 // This happens if the retention policy returns a priority of HIGH for all | |
745 // of the targets that have been recently used. This is the case, for | |
746 // example, when the list of priority sources is bigger than the current | |
747 // cache size. | |
748 return null; | |
749 } | |
750 return _recentlyUsed.removeAt(targetToRemove); | |
751 } | 737 } |
752 } | 738 } |
753 | 739 |
754 /** | |
755 * A policy objecy that determines how important it is for data to be retained | |
756 * in the analysis cache. | |
757 */ | |
758 abstract class CacheRetentionPolicy { | |
759 /** | |
760 * Return the priority of retaining the AST structure for the given [target] | |
761 * in the given [entry]. | |
762 */ | |
763 // TODO(brianwilkerson) Find a more general mechanism, probably based on task | |
764 // descriptors, to determine which data is still needed for analysis and which | |
765 // can be removed from the cache. Ideally we could (a) remove the need for | |
766 // this class and (b) be able to flush all result data (not just AST's). | |
767 RetentionPriority getAstPriority(AnalysisTarget target, CacheEntry entry); | |
768 } | |
769 | |
770 /** | |
771 * A retention policy that will keep AST's in the cache if there is analysis | |
772 * information that needs to be computed for a source, where the computation is | |
773 * dependent on having the AST. | |
774 */ | |
775 class DefaultRetentionPolicy implements CacheRetentionPolicy { | |
776 /** | |
777 * An instance of this class that can be shared. | |
778 */ | |
779 static const DefaultRetentionPolicy POLICY = const DefaultRetentionPolicy(); | |
780 | |
781 /** | |
782 * Initialize a newly created instance of this class. | |
783 */ | |
784 const DefaultRetentionPolicy(); | |
785 | |
786 // TODO(brianwilkerson) Implement or delete this. | |
787 // /** | |
788 // * Return `true` if there is analysis information in the given entry that ne
eds to be | |
789 // * computed, where the computation is dependent on having the AST. | |
790 // * | |
791 // * @param dartEntry the entry being tested | |
792 // * @return `true` if there is analysis information that needs to be computed
from the AST | |
793 // */ | |
794 // bool astIsNeeded(DartEntry dartEntry) => | |
795 // dartEntry.hasInvalidData(DartEntry.HINTS) || | |
796 // dartEntry.hasInvalidData(DartEntry.LINTS) || | |
797 // dartEntry.hasInvalidData(DartEntry.VERIFICATION_ERRORS) || | |
798 // dartEntry.hasInvalidData(DartEntry.RESOLUTION_ERRORS); | |
799 | |
800 @override | |
801 RetentionPriority getAstPriority(AnalysisTarget target, CacheEntry entry) { | |
802 // TODO(brianwilkerson) Implement or replace this. | |
803 // if (sourceEntry is DartEntry) { | |
804 // DartEntry dartEntry = sourceEntry; | |
805 // if (astIsNeeded(dartEntry)) { | |
806 // return RetentionPriority.MEDIUM; | |
807 // } | |
808 // } | |
809 // return RetentionPriority.LOW; | |
810 return RetentionPriority.MEDIUM; | |
811 } | |
812 } | |
813 | |
814 /** | 740 /** |
815 * The data about a single analysis result that is stored in a [CacheEntry]. | 741 * The data about a single analysis result that is stored in a [CacheEntry]. |
816 */ | 742 */ |
817 // TODO(brianwilkerson) Consider making this a generic class so that the value | 743 // TODO(brianwilkerson) Consider making this a generic class so that the value |
818 // can be typed. | 744 // can be typed. |
819 class ResultData { | 745 class ResultData { |
820 /** | 746 /** |
821 * The [ResultDescriptor] this result is for. | 747 * The [ResultDescriptor] this result is for. |
822 */ | 748 */ |
823 final ResultDescriptor descriptor; | 749 final ResultDescriptor descriptor; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
859 } | 785 } |
860 | 786 |
861 /** | 787 /** |
862 * Add the given [result] to the list of dependent results. | 788 * Add the given [result] to the list of dependent results. |
863 */ | 789 */ |
864 void addDependentResult(TargetedResult result) { | 790 void addDependentResult(TargetedResult result) { |
865 dependentResults.add(result); | 791 dependentResults.add(result); |
866 } | 792 } |
867 | 793 |
868 /** | 794 /** |
| 795 * Flush this value. |
| 796 */ |
| 797 void flush() { |
| 798 state = CacheState.FLUSHED; |
| 799 value = descriptor.defaultValue; |
| 800 } |
| 801 |
| 802 /** |
869 * Invalidate this [ResultData] that corresponds to [thisResult] and | 803 * Invalidate this [ResultData] that corresponds to [thisResult] and |
870 * propagate invalidation to the results that depend on this one. | 804 * propagate invalidation to the results that depend on this one. |
871 */ | 805 */ |
872 void invalidate( | 806 void invalidate(CachePartition partition, TargetedResult thisResult, |
873 AnalysisCache cache, TargetedResult thisResult, CacheState newState) { | 807 CacheState newState) { |
874 // Invalidate this result. | 808 // Invalidate this result. |
875 state = newState; | 809 state = newState; |
876 value = descriptor.defaultValue; | 810 value = descriptor.defaultValue; |
877 // Stop depending on other results. | 811 // Stop depending on other results. |
878 List<TargetedResult> dependedOnResults = this.dependedOnResults; | 812 List<TargetedResult> dependedOnResults = this.dependedOnResults; |
879 this.dependedOnResults = <TargetedResult>[]; | 813 this.dependedOnResults = <TargetedResult>[]; |
880 dependedOnResults.forEach((TargetedResult dependedOnResult) { | 814 dependedOnResults.forEach((TargetedResult dependedOnResult) { |
881 ResultData data = cache._getDataFor(dependedOnResult); | 815 ResultData data = partition._getDataFor(dependedOnResult); |
882 data.removeDependentResult(thisResult); | 816 data.removeDependentResult(thisResult); |
883 }); | 817 }); |
884 // Invalidate results that depend on this result. | 818 // Invalidate results that depend on this result. |
885 List<TargetedResult> dependentResults = this.dependentResults; | 819 List<TargetedResult> dependentResults = this.dependentResults; |
886 this.dependentResults = <TargetedResult>[]; | 820 this.dependentResults = <TargetedResult>[]; |
887 dependentResults.forEach((TargetedResult dependentResult) { | 821 dependentResults.forEach((TargetedResult dependentResult) { |
888 ResultData data = cache._getDataFor(dependentResult); | 822 ResultData data = partition._getDataFor(dependentResult); |
889 data.invalidate(cache, dependentResult, newState); | 823 data.invalidate(partition, dependentResult, newState); |
890 }); | 824 }); |
891 } | 825 } |
892 | 826 |
893 /** | 827 /** |
894 * Remove the given [result] from the list of dependent results. | 828 * Remove the given [result] from the list of dependent results. |
895 */ | 829 */ |
896 void removeDependentResult(TargetedResult result) { | 830 void removeDependentResult(TargetedResult result) { |
897 dependentResults.remove(result); | 831 dependentResults.remove(result); |
898 } | 832 } |
899 | 833 |
900 /** | 834 /** |
901 * Set the [dependedOn] on which this result depends. | 835 * Set the [dependedOn] on which this result depends. |
902 */ | 836 */ |
903 void setDependedOnResults(AnalysisCache cache, TargetedResult thisResult, | 837 void setDependedOnResults(CachePartition partition, TargetedResult thisResult, |
904 List<TargetedResult> dependedOn) { | 838 List<TargetedResult> dependedOn) { |
905 dependedOnResults.forEach((TargetedResult dependedOnResult) { | 839 dependedOnResults.forEach((TargetedResult dependedOnResult) { |
906 ResultData data = cache._getDataFor(dependedOnResult); | 840 ResultData data = partition._getDataFor(dependedOnResult); |
907 data.removeDependentResult(thisResult); | 841 data.removeDependentResult(thisResult); |
908 }); | 842 }); |
909 dependedOnResults = dependedOn; | 843 dependedOnResults = dependedOn; |
910 dependedOnResults.forEach((TargetedResult dependentResult) { | 844 dependedOnResults.forEach((TargetedResult dependentResult) { |
911 ResultData data = cache._getDataFor(dependentResult); | 845 ResultData data = partition._getDataFor(dependentResult); |
912 data.addDependentResult(thisResult); | 846 data.addDependentResult(thisResult); |
913 }); | 847 }); |
914 } | 848 } |
915 } | 849 } |
916 | 850 |
917 /** | 851 /** |
918 * A cache partition that contains all of the targets in the SDK. | 852 * A cache partition that contains all of the targets in the SDK. |
919 */ | 853 */ |
920 class SdkCachePartition extends CachePartition { | 854 class SdkCachePartition extends CachePartition { |
921 /** | 855 /** |
922 * Initialize a newly created cache partition, belonging to the given | 856 * Initialize a newly created cache partition, belonging to the given |
923 * [context]. The partition will maintain at most [maxCacheSize] AST | 857 * [context]. |
924 * structures in the cache. | |
925 */ | 858 */ |
926 SdkCachePartition(InternalAnalysisContext context, int maxCacheSize) | 859 SdkCachePartition(InternalAnalysisContext context) : super(context); |
927 : super(context, maxCacheSize, DefaultRetentionPolicy.POLICY); | |
928 | 860 |
929 @override | 861 @override |
930 bool contains(AnalysisTarget target) { | 862 bool contains(AnalysisTarget target) { |
931 Source source = target.source; | 863 Source source = target.source; |
932 return source != null && source.isInSystemLibrary; | 864 return source != null && source.isInSystemLibrary; |
933 } | 865 } |
934 } | 866 } |
935 | 867 |
936 /** | 868 /** |
937 * A specification of a specific result computed for a specific target. | 869 * A specification of a specific result computed for a specific target. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
972 @override | 904 @override |
973 String toString() => '$result for $target'; | 905 String toString() => '$result for $target'; |
974 } | 906 } |
975 | 907 |
976 /** | 908 /** |
977 * A cache partition that contains all targets not contained in other partitions
. | 909 * A cache partition that contains all targets not contained in other partitions
. |
978 */ | 910 */ |
979 class UniversalCachePartition extends CachePartition { | 911 class UniversalCachePartition extends CachePartition { |
980 /** | 912 /** |
981 * Initialize a newly created cache partition, belonging to the given | 913 * Initialize a newly created cache partition, belonging to the given |
982 * [context]. The partition will maintain at most [maxCacheSize] AST | 914 * [context]. |
983 * structures in the cache, using the [retentionPolicy] to determine which | |
984 * AST structures to flush. | |
985 */ | 915 */ |
986 UniversalCachePartition(InternalAnalysisContext context, int maxCacheSize, | 916 UniversalCachePartition(InternalAnalysisContext context) : super(context); |
987 CacheRetentionPolicy retentionPolicy) | |
988 : super(context, maxCacheSize, retentionPolicy); | |
989 | 917 |
990 @override | 918 @override |
991 bool contains(AnalysisTarget target) => true; | 919 bool contains(AnalysisTarget target) => true; |
992 } | 920 } |
OLD | NEW |