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 |