| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'dart:core'; | 7 import 'dart:core'; |
| 8 import 'dart:io' as io; | 8 import 'dart:io' as io; |
| 9 import 'dart:math' show max; | 9 import 'dart:math' show max; |
| 10 | 10 |
| 11 import 'package:analysis_server/protocol/protocol.dart'; | 11 import 'package:analysis_server/protocol/protocol.dart'; |
| 12 import 'package:analysis_server/protocol/protocol_generated.dart' | 12 import 'package:analysis_server/protocol/protocol_generated.dart' |
| 13 hide AnalysisOptions; | 13 hide AnalysisOptions; |
| 14 import 'package:analysis_server/src/analysis_logger.dart'; | 14 import 'package:analysis_server/src/analysis_logger.dart'; |
| 15 import 'package:analysis_server/src/channel/channel.dart'; | 15 import 'package:analysis_server/src/channel/channel.dart'; |
| 16 import 'package:analysis_server/src/collections.dart'; | 16 import 'package:analysis_server/src/collections.dart'; |
| 17 import 'package:analysis_server/src/computer/computer_highlights.dart'; | 17 import 'package:analysis_server/src/computer/computer_highlights.dart'; |
| 18 import 'package:analysis_server/src/computer/computer_highlights2.dart'; | 18 import 'package:analysis_server/src/computer/computer_highlights2.dart'; |
| 19 import 'package:analysis_server/src/computer/computer_outline.dart'; | 19 import 'package:analysis_server/src/computer/computer_outline.dart'; |
| 20 import 'package:analysis_server/src/computer/new_notifications.dart'; | 20 import 'package:analysis_server/src/computer/new_notifications.dart'; |
| 21 import 'package:analysis_server/src/context_manager.dart'; | 21 import 'package:analysis_server/src/context_manager.dart'; |
| 22 import 'package:analysis_server/src/domains/analysis/navigation.dart'; | 22 import 'package:analysis_server/src/domains/analysis/navigation.dart'; |
| 23 import 'package:analysis_server/src/domains/analysis/navigation_dart.dart'; | 23 import 'package:analysis_server/src/domains/analysis/navigation_dart.dart'; |
| 24 import 'package:analysis_server/src/domains/analysis/occurrences.dart'; | 24 import 'package:analysis_server/src/domains/analysis/occurrences.dart'; |
| 25 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart'; | 25 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart'; |
| 26 import 'package:analysis_server/src/operation/operation.dart'; | |
| 27 import 'package:analysis_server/src/operation/operation_analysis.dart'; | 26 import 'package:analysis_server/src/operation/operation_analysis.dart'; |
| 28 import 'package:analysis_server/src/operation/operation_queue.dart'; | |
| 29 import 'package:analysis_server/src/plugin/notification_manager.dart'; | 27 import 'package:analysis_server/src/plugin/notification_manager.dart'; |
| 30 import 'package:analysis_server/src/plugin/plugin_manager.dart'; | 28 import 'package:analysis_server/src/plugin/plugin_manager.dart'; |
| 31 import 'package:analysis_server/src/plugin/plugin_watcher.dart'; | 29 import 'package:analysis_server/src/plugin/plugin_watcher.dart'; |
| 32 import 'package:analysis_server/src/plugin/server_plugin.dart'; | 30 import 'package:analysis_server/src/plugin/server_plugin.dart'; |
| 33 import 'package:analysis_server/src/protocol_server.dart' as server; | 31 import 'package:analysis_server/src/protocol_server.dart' as server; |
| 34 import 'package:analysis_server/src/server/diagnostic_server.dart'; | 32 import 'package:analysis_server/src/server/diagnostic_server.dart'; |
| 35 import 'package:analysis_server/src/services/correction/namespace.dart'; | 33 import 'package:analysis_server/src/services/correction/namespace.dart'; |
| 36 import 'package:analysis_server/src/services/index/index.dart'; | 34 import 'package:analysis_server/src/services/index/index.dart'; |
| 37 import 'package:analysis_server/src/services/search/search_engine.dart'; | 35 import 'package:analysis_server/src/services/search/search_engine.dart'; |
| 38 import 'package:analysis_server/src/services/search/search_engine_internal.dart'
; | 36 import 'package:analysis_server/src/services/search/search_engine_internal.dart'
; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 * [CommunicationChannel] for analysis requests and process them. | 95 * [CommunicationChannel] for analysis requests and process them. |
| 98 */ | 96 */ |
| 99 class AnalysisServer { | 97 class AnalysisServer { |
| 100 /** | 98 /** |
| 101 * The version of the analysis server. The value should be replaced | 99 * The version of the analysis server. The value should be replaced |
| 102 * automatically during the build. | 100 * automatically during the build. |
| 103 */ | 101 */ |
| 104 static final String VERSION = '1.18.1'; | 102 static final String VERSION = '1.18.1'; |
| 105 | 103 |
| 106 /** | 104 /** |
| 107 * The number of milliseconds to perform operations before inserting | |
| 108 * a 1 millisecond delay so that the VM and dart:io can deliver content | |
| 109 * to stdin. This should be removed once the underlying problem is fixed. | |
| 110 */ | |
| 111 static int performOperationDelayFrequency = 25; | |
| 112 | |
| 113 /** | |
| 114 * The options of this server instance. | 105 * The options of this server instance. |
| 115 */ | 106 */ |
| 116 AnalysisServerOptions options; | 107 AnalysisServerOptions options; |
| 117 | 108 |
| 118 /** | 109 /** |
| 119 * The channel from which requests are received and to which responses should | 110 * The channel from which requests are received and to which responses should |
| 120 * be sent. | 111 * be sent. |
| 121 */ | 112 */ |
| 122 final ServerCommunicationChannel channel; | 113 final ServerCommunicationChannel channel; |
| 123 | 114 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 188 * The object used to manage the SDK's known to this server. | 179 * The object used to manage the SDK's known to this server. |
| 189 */ | 180 */ |
| 190 DartSdkManager sdkManager; | 181 DartSdkManager sdkManager; |
| 191 | 182 |
| 192 /** | 183 /** |
| 193 * The instrumentation service that is to be used by this analysis server. | 184 * The instrumentation service that is to be used by this analysis server. |
| 194 */ | 185 */ |
| 195 final InstrumentationService instrumentationService; | 186 final InstrumentationService instrumentationService; |
| 196 | 187 |
| 197 /** | 188 /** |
| 198 * A queue of the operations to perform in this server. | |
| 199 */ | |
| 200 ServerOperationQueue operationQueue; | |
| 201 | |
| 202 /** | |
| 203 * True if there is a pending future which will execute [performOperation]. | |
| 204 */ | |
| 205 bool performOperationPending = false; | |
| 206 | |
| 207 /** | |
| 208 * A set of the [ServerService]s to send notifications for. | 189 * A set of the [ServerService]s to send notifications for. |
| 209 */ | 190 */ |
| 210 Set<ServerService> serverServices = new HashSet<ServerService>(); | 191 Set<ServerService> serverServices = new HashSet<ServerService>(); |
| 211 | 192 |
| 212 /** | 193 /** |
| 213 * A set of the [GeneralAnalysisService]s to send notifications for. | 194 * A set of the [GeneralAnalysisService]s to send notifications for. |
| 214 */ | 195 */ |
| 215 Set<GeneralAnalysisService> generalAnalysisServices = | 196 Set<GeneralAnalysisService> generalAnalysisServices = |
| 216 new HashSet<GeneralAnalysisService>(); | 197 new HashSet<GeneralAnalysisService>(); |
| 217 | 198 |
| 218 /** | 199 /** |
| 219 * A table mapping [AnalysisService]s to the file paths for which these | 200 * A table mapping [AnalysisService]s to the file paths for which these |
| 220 * notifications should be sent. | 201 * notifications should be sent. |
| 221 */ | 202 */ |
| 222 Map<AnalysisService, Set<String>> analysisServices = | 203 Map<AnalysisService, Set<String>> analysisServices = |
| 223 new HashMap<AnalysisService, Set<String>>(); | 204 new HashMap<AnalysisService, Set<String>>(); |
| 224 | 205 |
| 225 /** | 206 /** |
| 226 * A table mapping [AnalysisContext]s to the completers that should be | |
| 227 * completed when analysis of this context is finished. | |
| 228 */ | |
| 229 Map<AnalysisContext, Completer<AnalysisDoneReason>> | |
| 230 contextAnalysisDoneCompleters = | |
| 231 new HashMap<AnalysisContext, Completer<AnalysisDoneReason>>(); | |
| 232 | |
| 233 /** | |
| 234 * Performance information before initial analysis is complete. | 207 * Performance information before initial analysis is complete. |
| 235 */ | 208 */ |
| 236 ServerPerformance performanceDuringStartup = new ServerPerformance(); | 209 ServerPerformance performanceDuringStartup = new ServerPerformance(); |
| 237 | 210 |
| 238 /** | 211 /** |
| 239 * Performance information after initial analysis is complete | 212 * Performance information after initial analysis is complete |
| 240 * or `null` if the initial analysis is not yet complete | 213 * or `null` if the initial analysis is not yet complete |
| 241 */ | 214 */ |
| 242 ServerPerformance performanceAfterStartup; | 215 ServerPerformance performanceAfterStartup; |
| 243 | 216 |
| 244 /** | 217 /** |
| 245 * A [RecentBuffer] of the most recent exceptions encountered by the analysis | 218 * A [RecentBuffer] of the most recent exceptions encountered by the analysis |
| 246 * server. | 219 * server. |
| 247 */ | 220 */ |
| 248 final RecentBuffer<ServerException> exceptions = new RecentBuffer(10); | 221 final RecentBuffer<ServerException> exceptions = new RecentBuffer(10); |
| 249 | 222 |
| 250 /** | 223 /** |
| 251 * The class into which performance information is currently being recorded. | 224 * The class into which performance information is currently being recorded. |
| 252 * During startup, this will be the same as [performanceDuringStartup] | 225 * During startup, this will be the same as [performanceDuringStartup] |
| 253 * and after startup is complete, this switches to [performanceAfterStartup]. | 226 * and after startup is complete, this switches to [performanceAfterStartup]. |
| 254 */ | 227 */ |
| 255 ServerPerformance _performance; | 228 ServerPerformance _performance; |
| 256 | 229 |
| 257 /** | 230 /** |
| 258 * The [Completer] that completes when analysis is complete. | 231 * The [Completer] that completes when analysis is complete. |
| 259 */ | 232 */ |
| 260 Completer _onAnalysisCompleteCompleter; | 233 Completer _onAnalysisCompleteCompleter; |
| 261 | 234 |
| 262 /** | 235 /** |
| 263 * The [Completer] that completes when the next operation is performed. | |
| 264 */ | |
| 265 Completer _test_onOperationPerformedCompleter; | |
| 266 | |
| 267 /** | |
| 268 * The controller that is notified when analysis is started. | 236 * The controller that is notified when analysis is started. |
| 269 */ | 237 */ |
| 270 StreamController<bool> _onAnalysisStartedController; | 238 StreamController<bool> _onAnalysisStartedController; |
| 271 | 239 |
| 272 /** | 240 /** |
| 273 * The controller that is notified when a single file has been analyzed. | 241 * The controller that is notified when a single file has been analyzed. |
| 274 */ | 242 */ |
| 275 StreamController<ChangeNotice> _onFileAnalyzedController; | 243 StreamController<ChangeNotice> _onFileAnalyzedController; |
| 276 | 244 |
| 277 /** | 245 /** |
| 278 * True if any exceptions thrown by analysis should be propagated up the call | |
| 279 * stack. | |
| 280 */ | |
| 281 bool rethrowExceptions; | |
| 282 | |
| 283 /** | |
| 284 * The next time (milliseconds since epoch) after which the analysis server | |
| 285 * should pause so that pending requests can be fetched by the system. | |
| 286 */ | |
| 287 // Add 1 sec to prevent delay from impacting short running tests | |
| 288 int _nextPerformOperationDelayTime = | |
| 289 new DateTime.now().millisecondsSinceEpoch + 1000; | |
| 290 | |
| 291 /** | |
| 292 * The content overlay for all analysis drivers. | 246 * The content overlay for all analysis drivers. |
| 293 */ | 247 */ |
| 294 final nd.FileContentOverlay fileContentOverlay = new nd.FileContentOverlay(); | 248 final nd.FileContentOverlay fileContentOverlay = new nd.FileContentOverlay(); |
| 295 | 249 |
| 296 /** | 250 /** |
| 297 * The current state of overlays from the client. This is used as the | 251 * The current state of overlays from the client. This is used as the |
| 298 * content cache for all contexts. | 252 * content cache for all contexts. |
| 299 */ | 253 */ |
| 300 final ContentCache overlayState = new ContentCache(); | 254 final ContentCache overlayState = new ContentCache(); |
| 301 | 255 |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 this.channel, | 344 this.channel, |
| 391 this.resourceProvider, | 345 this.resourceProvider, |
| 392 PubPackageMapProvider packageMapProvider, | 346 PubPackageMapProvider packageMapProvider, |
| 393 this.index, | 347 this.index, |
| 394 this.serverPlugin, | 348 this.serverPlugin, |
| 395 this.options, | 349 this.options, |
| 396 this.sdkManager, | 350 this.sdkManager, |
| 397 this.instrumentationService, | 351 this.instrumentationService, |
| 398 {this.diagnosticServer, | 352 {this.diagnosticServer, |
| 399 ResolverProvider fileResolverProvider: null, | 353 ResolverProvider fileResolverProvider: null, |
| 400 ResolverProvider packageResolverProvider: null, | 354 ResolverProvider packageResolverProvider: null}) |
| 401 this.rethrowExceptions: true}) | |
| 402 : notificationManager = | 355 : notificationManager = |
| 403 new NotificationManager(channel, resourceProvider) { | 356 new NotificationManager(channel, resourceProvider) { |
| 404 _performance = performanceDuringStartup; | 357 _performance = performanceDuringStartup; |
| 405 | 358 |
| 406 pluginManager = new PluginManager( | 359 pluginManager = new PluginManager( |
| 407 resourceProvider, | 360 resourceProvider, |
| 408 _getByteStorePath(), | 361 _getByteStorePath(), |
| 409 sdkManager.defaultSdkDirectory, | 362 sdkManager.defaultSdkDirectory, |
| 410 notificationManager, | 363 notificationManager, |
| 411 instrumentationService); | 364 instrumentationService); |
| 412 PluginWatcher pluginWatcher = | 365 PluginWatcher pluginWatcher = |
| 413 new PluginWatcher(resourceProvider, pluginManager); | 366 new PluginWatcher(resourceProvider, pluginManager); |
| 414 | 367 |
| 415 defaultContextOptions.incremental = true; | 368 defaultContextOptions.incremental = true; |
| 416 defaultContextOptions.incrementalApi = | 369 defaultContextOptions.incrementalApi = |
| 417 options.enableIncrementalResolutionApi; | 370 options.enableIncrementalResolutionApi; |
| 418 defaultContextOptions.incrementalValidation = | 371 defaultContextOptions.incrementalValidation = |
| 419 options.enableIncrementalResolutionValidation; | 372 options.enableIncrementalResolutionValidation; |
| 420 defaultContextOptions.generateImplicitErrors = false; | 373 defaultContextOptions.generateImplicitErrors = false; |
| 421 operationQueue = new ServerOperationQueue(); | |
| 422 | 374 |
| 423 { | 375 { |
| 424 String name = options.newAnalysisDriverLog; | 376 String name = options.newAnalysisDriverLog; |
| 425 StringSink sink = new NullStringSink(); | 377 StringSink sink = new NullStringSink(); |
| 426 if (name != null) { | 378 if (name != null) { |
| 427 if (name == 'stdout') { | 379 if (name == 'stdout') { |
| 428 sink = io.stdout; | 380 sink = io.stdout; |
| 429 } else if (name.startsWith('file:')) { | 381 } else if (name.startsWith('file:')) { |
| 430 String path = name.substring('file:'.length); | 382 String path = name.substring('file:'.length); |
| 431 sink = new io.File(path).openWrite(mode: io.FileMode.APPEND); | 383 sink = new io.File(path).openWrite(mode: io.FileMode.APPEND); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; | 488 Stream get onFileAnalyzed => _onFileAnalyzedController.stream; |
| 537 | 489 |
| 538 /** | 490 /** |
| 539 * The stream that is notified when a single file has been changed. This | 491 * The stream that is notified when a single file has been changed. This |
| 540 * exists as a temporary stopgap for plugins, until the official plugin API is | 492 * exists as a temporary stopgap for plugins, until the official plugin API is |
| 541 * complete. | 493 * complete. |
| 542 */ | 494 */ |
| 543 Stream get onFileChanged => _onFileChangedController.stream; | 495 Stream get onFileChanged => _onFileChangedController.stream; |
| 544 | 496 |
| 545 /** | 497 /** |
| 546 * The [Future] that completes when the next operation is performed. | |
| 547 */ | |
| 548 Future get test_onOperationPerformed { | |
| 549 if (_test_onOperationPerformedCompleter == null) { | |
| 550 _test_onOperationPerformedCompleter = new Completer(); | |
| 551 } | |
| 552 return _test_onOperationPerformedCompleter.future; | |
| 553 } | |
| 554 | |
| 555 /** | |
| 556 * Return the total time the server's been alive. | 498 * Return the total time the server's been alive. |
| 557 */ | 499 */ |
| 558 Duration get uptime { | 500 Duration get uptime { |
| 559 DateTime start = new DateTime.fromMillisecondsSinceEpoch( | 501 DateTime start = new DateTime.fromMillisecondsSinceEpoch( |
| 560 performanceDuringStartup.startTime); | 502 performanceDuringStartup.startTime); |
| 561 return new DateTime.now().difference(start); | 503 return new DateTime.now().difference(start); |
| 562 } | 504 } |
| 563 | 505 |
| 564 /** | 506 /** |
| 565 * Adds the given [ServerOperation] to the queue, but does not schedule | |
| 566 * operations execution. | |
| 567 */ | |
| 568 void addOperation(ServerOperation operation) { | |
| 569 operationQueue.add(operation); | |
| 570 } | |
| 571 | |
| 572 /** | |
| 573 * The socket from which requests are being read has been closed. | 507 * The socket from which requests are being read has been closed. |
| 574 */ | 508 */ |
| 575 void done() { | 509 void done() { |
| 576 index?.stop(); | 510 index?.stop(); |
| 577 running = false; | 511 running = false; |
| 578 } | 512 } |
| 579 | 513 |
| 580 /** | 514 /** |
| 581 * There was an error related to the socket from which requests are being | 515 * There was an error related to the socket from which requests are being |
| 582 * read. | 516 * read. |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 */ | 715 */ |
| 782 bool hasAnalysisSubscription(AnalysisService service, String file) { | 716 bool hasAnalysisSubscription(AnalysisService service, String file) { |
| 783 Set<String> files = analysisServices[service]; | 717 Set<String> files = analysisServices[service]; |
| 784 return files != null && files.contains(file); | 718 return files != null && files.contains(file); |
| 785 } | 719 } |
| 786 | 720 |
| 787 /** | 721 /** |
| 788 * Return `true` if analysis is complete. | 722 * Return `true` if analysis is complete. |
| 789 */ | 723 */ |
| 790 bool isAnalysisComplete() { | 724 bool isAnalysisComplete() { |
| 791 return operationQueue.isEmpty && !analysisDriverScheduler.isAnalyzing; | 725 return !analysisDriverScheduler.isAnalyzing; |
| 792 } | 726 } |
| 793 | 727 |
| 794 /** | 728 /** |
| 795 * Return `true` if the given path is a valid `FilePath`. | 729 * Return `true` if the given path is a valid `FilePath`. |
| 796 * | 730 * |
| 797 * This means that it is absolute and normalized. | 731 * This means that it is absolute and normalized. |
| 798 */ | 732 */ |
| 799 bool isValidFilePath(String path) { | 733 bool isValidFilePath(String path) { |
| 800 return resourceProvider.absolutePathContext.isValid(path); | 734 return resourceProvider.absolutePathContext.isValid(path); |
| 801 } | 735 } |
| 802 | 736 |
| 803 /** | 737 /** |
| 804 * Perform the next available [ServerOperation]. | |
| 805 */ | |
| 806 void performOperation() { | |
| 807 assert(performOperationPending); | |
| 808 PerformanceTag.unknown.makeCurrent(); | |
| 809 performOperationPending = false; | |
| 810 if (!running) { | |
| 811 // An error has occurred, or the connection to the client has been | |
| 812 // closed, since this method was scheduled on the event queue. So | |
| 813 // don't do anything. Instead clear the operation queue. | |
| 814 operationQueue.clear(); | |
| 815 return; | |
| 816 } | |
| 817 // prepare next operation | |
| 818 ServerOperation operation = operationQueue.take(); | |
| 819 if (operation == null) { | |
| 820 // This can happen if the operation queue is cleared while the operation | |
| 821 // loop is in progress. No problem; we just need to exit the operation | |
| 822 // loop and wait for the next operation to be added. | |
| 823 ServerPerformanceStatistics.idle.makeCurrent(); | |
| 824 return; | |
| 825 } | |
| 826 sendStatusNotification(operation); | |
| 827 // perform the operation | |
| 828 try { | |
| 829 operation.perform(this); | |
| 830 } catch (exception, stackTrace) { | |
| 831 sendServerErrorNotification( | |
| 832 'Failed to perform operation: $operation', exception, stackTrace, | |
| 833 fatal: true); | |
| 834 if (rethrowExceptions) { | |
| 835 throw new AnalysisException('Unexpected exception during analysis', | |
| 836 new CaughtException(exception, stackTrace)); | |
| 837 } | |
| 838 shutdown(); | |
| 839 } finally { | |
| 840 if (_test_onOperationPerformedCompleter != null) { | |
| 841 _test_onOperationPerformedCompleter.complete(operation); | |
| 842 _test_onOperationPerformedCompleter = null; | |
| 843 } | |
| 844 if (!operationQueue.isEmpty) { | |
| 845 ServerPerformanceStatistics.intertask.makeCurrent(); | |
| 846 _schedulePerformOperation(); | |
| 847 } else { | |
| 848 if (generalAnalysisServices | |
| 849 .contains(GeneralAnalysisService.ANALYZED_FILES)) { | |
| 850 sendAnalysisNotificationAnalyzedFiles(this); | |
| 851 } | |
| 852 sendStatusNotification(null); | |
| 853 _scheduleAnalysisImplementedNotification(); | |
| 854 if (_onAnalysisCompleteCompleter != null) { | |
| 855 _onAnalysisCompleteCompleter.complete(); | |
| 856 _onAnalysisCompleteCompleter = null; | |
| 857 } | |
| 858 ServerPerformanceStatistics.idle.makeCurrent(); | |
| 859 } | |
| 860 } | |
| 861 } | |
| 862 | |
| 863 /** | |
| 864 * Trigger reanalysis of all files in the given list of analysis [roots], or | 738 * Trigger reanalysis of all files in the given list of analysis [roots], or |
| 865 * everything if the analysis roots is `null`. | 739 * everything if the analysis roots is `null`. |
| 866 */ | 740 */ |
| 867 void reanalyze(List<Resource> roots) { | 741 void reanalyze(List<Resource> roots) { |
| 868 // Clear any operations that are pending. | |
| 869 if (roots == null) { | |
| 870 operationQueue.clear(); | |
| 871 } else { | |
| 872 // TODO(brianwilkerson) All of the contexts returned by _getContexts will | |
| 873 // be null. If we are still using the operation queue, then this needs to | |
| 874 // be changed to use drivers. | |
| 875 // for (AnalysisContext context in _getContexts(roots)) { | |
| 876 // operationQueue.contextRemoved(context); | |
| 877 // } | |
| 878 } | |
| 879 // Instruct the contextDirectoryManager to rebuild all contexts from | 742 // Instruct the contextDirectoryManager to rebuild all contexts from |
| 880 // scratch. | 743 // scratch. |
| 881 contextManager.refresh(roots); | 744 contextManager.refresh(roots); |
| 882 } | 745 } |
| 883 | 746 |
| 884 /** | 747 /** |
| 885 * Schedule cache consistency validation in [context]. | |
| 886 * The most of the validation must be done asynchronously. | |
| 887 */ | |
| 888 void scheduleCacheConsistencyValidation(AnalysisContext context) { | |
| 889 if (context is InternalAnalysisContext) { | |
| 890 CacheConsistencyValidator validator = context.cacheConsistencyValidator; | |
| 891 List<Source> sources = validator.getSourcesToComputeModificationTimes(); | |
| 892 // Compute modification times and notify the validator asynchronously. | |
| 893 new Future(() async { | |
| 894 try { | |
| 895 List<int> modificationTimes = | |
| 896 await resourceProvider.getModificationTimes(sources); | |
| 897 bool cacheInconsistencyFixed = validator | |
| 898 .sourceModificationTimesComputed(sources, modificationTimes); | |
| 899 if (cacheInconsistencyFixed) { | |
| 900 scheduleOperation(new PerformAnalysisOperation(context, false)); | |
| 901 } | |
| 902 } catch (exception, stackTrace) { | |
| 903 sendServerErrorNotification( | |
| 904 'Failed to check cache consistency', exception, stackTrace); | |
| 905 } | |
| 906 }); | |
| 907 } | |
| 908 } | |
| 909 | |
| 910 /** | |
| 911 * Schedules execution of the given [ServerOperation]. | |
| 912 */ | |
| 913 void scheduleOperation(ServerOperation operation) { | |
| 914 addOperation(operation); | |
| 915 _schedulePerformOperation(); | |
| 916 } | |
| 917 | |
| 918 /** | |
| 919 * Schedules analysis of the given context. | |
| 920 */ | |
| 921 void schedulePerformAnalysisOperation(AnalysisContext context) { | |
| 922 _onAnalysisStartedController.add(true); | |
| 923 scheduleOperation(new PerformAnalysisOperation(context, false)); | |
| 924 } | |
| 925 | |
| 926 /** | |
| 927 * This method is called when analysis of the given [AnalysisContext] is | |
| 928 * done. | |
| 929 */ | |
| 930 void sendContextAnalysisDoneNotifications( | |
| 931 AnalysisContext context, AnalysisDoneReason reason) { | |
| 932 Completer<AnalysisDoneReason> completer = | |
| 933 contextAnalysisDoneCompleters.remove(context); | |
| 934 if (completer != null) { | |
| 935 completer.complete(reason); | |
| 936 } | |
| 937 } | |
| 938 | |
| 939 /** | |
| 940 * Send the given [notification] to the client. | 748 * Send the given [notification] to the client. |
| 941 */ | 749 */ |
| 942 void sendNotification(Notification notification) { | 750 void sendNotification(Notification notification) { |
| 943 channel.sendNotification(notification); | 751 channel.sendNotification(notification); |
| 944 } | 752 } |
| 945 | 753 |
| 946 /** | 754 /** |
| 947 * Send the given [response] to the client. | 755 * Send the given [response] to the client. |
| 948 */ | 756 */ |
| 949 void sendResponse(Response response) { | 757 void sendResponse(Response response) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 972 .toNotification()); | 780 .toNotification()); |
| 973 | 781 |
| 974 // remember the last few exceptions | 782 // remember the last few exceptions |
| 975 if (exception is CaughtException) { | 783 if (exception is CaughtException) { |
| 976 stackTrace ??= exception.stackTrace; | 784 stackTrace ??= exception.stackTrace; |
| 977 } | 785 } |
| 978 exceptions.add(new ServerException(message, exception, stackTrace, fatal)); | 786 exceptions.add(new ServerException(message, exception, stackTrace, fatal)); |
| 979 } | 787 } |
| 980 | 788 |
| 981 /** | 789 /** |
| 982 * Send status notification to the client. The `operation` is the operation | |
| 983 * being performed or `null` if analysis is complete. | |
| 984 */ | |
| 985 void sendStatusNotification(ServerOperation operation) { | |
| 986 // Only send status when subscribed. | |
| 987 if (!serverServices.contains(ServerService.STATUS)) { | |
| 988 return; | |
| 989 } | |
| 990 // Only send status when it changes | |
| 991 bool isAnalyzing = operation != null; | |
| 992 if (statusAnalyzing == isAnalyzing) { | |
| 993 return; | |
| 994 } | |
| 995 statusAnalyzing = isAnalyzing; | |
| 996 AnalysisStatus analysis = new AnalysisStatus(isAnalyzing); | |
| 997 channel.sendNotification( | |
| 998 new ServerStatusParams(analysis: analysis).toNotification()); | |
| 999 } | |
| 1000 | |
| 1001 /** | |
| 1002 * Send status notification to the client. The state of analysis is given by | 790 * Send status notification to the client. The state of analysis is given by |
| 1003 * the [status] information. | 791 * the [status] information. |
| 1004 */ | 792 */ |
| 1005 void sendStatusNotificationNew(nd.AnalysisStatus status) { | 793 void sendStatusNotificationNew(nd.AnalysisStatus status) { |
| 1006 if (status.isAnalyzing) { | 794 if (status.isAnalyzing) { |
| 1007 _onAnalysisStartedController.add(true); | 795 _onAnalysisStartedController.add(true); |
| 1008 } | 796 } |
| 1009 if (_onAnalysisCompleteCompleter != null && !status.isAnalyzing) { | 797 if (_onAnalysisCompleteCompleter != null && !status.isAnalyzing) { |
| 1010 _onAnalysisCompleteCompleter.complete(); | 798 _onAnalysisCompleteCompleter.complete(); |
| 1011 _onAnalysisCompleteCompleter = null; | 799 _onAnalysisCompleteCompleter = null; |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 } | 912 } |
| 1125 // Defer closing the channel and shutting down the instrumentation server so | 913 // Defer closing the channel and shutting down the instrumentation server so |
| 1126 // that the shutdown response can be sent and logged. | 914 // that the shutdown response can be sent and logged. |
| 1127 new Future(() { | 915 new Future(() { |
| 1128 instrumentationService.shutdown(); | 916 instrumentationService.shutdown(); |
| 1129 channel.close(); | 917 channel.close(); |
| 1130 }); | 918 }); |
| 1131 } | 919 } |
| 1132 | 920 |
| 1133 /** | 921 /** |
| 1134 * Performs all scheduled analysis operations. | |
| 1135 */ | |
| 1136 void test_performAllAnalysisOperations() { | |
| 1137 while (true) { | |
| 1138 ServerOperation operation = operationQueue.takeIf((operation) { | |
| 1139 return operation is PerformAnalysisOperation; | |
| 1140 }); | |
| 1141 if (operation == null) { | |
| 1142 break; | |
| 1143 } | |
| 1144 operation.perform(this); | |
| 1145 } | |
| 1146 } | |
| 1147 | |
| 1148 /** | |
| 1149 * Implementation for `analysis.updateContent`. | 922 * Implementation for `analysis.updateContent`. |
| 1150 */ | 923 */ |
| 1151 void updateContent(String id, Map<String, dynamic> changes) { | 924 void updateContent(String id, Map<String, dynamic> changes) { |
| 1152 changes.forEach((file, change) { | 925 changes.forEach((file, change) { |
| 1153 // Prepare the new contents. | 926 // Prepare the new contents. |
| 1154 String oldContents = fileContentOverlay[file]; | 927 String oldContents = fileContentOverlay[file]; |
| 1155 String newContents; | 928 String newContents; |
| 1156 if (change is AddContentOverlay) { | 929 if (change is AddContentOverlay) { |
| 1157 newContents = change.content; | 930 newContents = change.content; |
| 1158 } else if (change is ChangeContentOverlay) { | 931 } else if (change is ChangeContentOverlay) { |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1267 } | 1040 } |
| 1268 | 1041 |
| 1269 _scheduleAnalysisImplementedNotification() async { | 1042 _scheduleAnalysisImplementedNotification() async { |
| 1270 Set<String> files = analysisServices[AnalysisService.IMPLEMENTED]; | 1043 Set<String> files = analysisServices[AnalysisService.IMPLEMENTED]; |
| 1271 if (files != null) { | 1044 if (files != null) { |
| 1272 scheduleImplementedNotification(this, files); | 1045 scheduleImplementedNotification(this, files); |
| 1273 } | 1046 } |
| 1274 } | 1047 } |
| 1275 | 1048 |
| 1276 /** | 1049 /** |
| 1277 * Schedules [performOperation] execution. | |
| 1278 */ | |
| 1279 void _schedulePerformOperation() { | |
| 1280 if (performOperationPending) { | |
| 1281 return; | |
| 1282 } | |
| 1283 /* | |
| 1284 * TODO (danrubel) Rip out this workaround once the underlying problem | |
| 1285 * is fixed. Currently, the VM and dart:io do not deliver content | |
| 1286 * on stdin in a timely manner if the event loop is busy. | |
| 1287 * To work around this problem, we delay for 1 millisecond | |
| 1288 * every 25 milliseconds. | |
| 1289 * | |
| 1290 * To disable this workaround and see the underlying problem, | |
| 1291 * set performOperationDelayFrequency to zero | |
| 1292 */ | |
| 1293 int now = new DateTime.now().millisecondsSinceEpoch; | |
| 1294 if (now > _nextPerformOperationDelayTime && | |
| 1295 performOperationDelayFrequency > 0) { | |
| 1296 _nextPerformOperationDelayTime = now + performOperationDelayFrequency; | |
| 1297 new Future.delayed(new Duration(milliseconds: 1), performOperation); | |
| 1298 } else { | |
| 1299 new Future(performOperation); | |
| 1300 } | |
| 1301 performOperationPending = true; | |
| 1302 } | |
| 1303 | |
| 1304 /** | |
| 1305 * Listen for context events and invalidate index. | 1050 * Listen for context events and invalidate index. |
| 1306 * | 1051 * |
| 1307 * It is possible that this method will do more in the future, e.g. listening | 1052 * It is possible that this method will do more in the future, e.g. listening |
| 1308 * for summary information and linking pre-indexed packages into the index, | 1053 * for summary information and linking pre-indexed packages into the index, |
| 1309 * but for now we only invalidate project specific index information. | 1054 * but for now we only invalidate project specific index information. |
| 1310 */ | 1055 */ |
| 1311 void _setupIndexInvalidation() { | 1056 void _setupIndexInvalidation() { |
| 1312 if (index == null) { | 1057 if (index == null) { |
| 1313 return; | 1058 return; |
| 1314 } | 1059 } |
| (...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1767 /** | 1512 /** |
| 1768 * The [PerformanceTag] for time spent in server request handlers. | 1513 * The [PerformanceTag] for time spent in server request handlers. |
| 1769 */ | 1514 */ |
| 1770 static PerformanceTag serverRequests = server.createChild('requests'); | 1515 static PerformanceTag serverRequests = server.createChild('requests'); |
| 1771 | 1516 |
| 1772 /** | 1517 /** |
| 1773 * The [PerformanceTag] for time spent in split store microtasks. | 1518 * The [PerformanceTag] for time spent in split store microtasks. |
| 1774 */ | 1519 */ |
| 1775 static PerformanceTag splitStore = new PerformanceTag('splitStore'); | 1520 static PerformanceTag splitStore = new PerformanceTag('splitStore'); |
| 1776 } | 1521 } |
| OLD | NEW |