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

Side by Side Diff: pkg/analysis_server/lib/src/analysis_server.dart

Issue 308003009: Add ServerOperation and queue. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove some priorities Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 library analysis.server; 5 library analysis.server;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'package:analysis_server/src/analysis_logger.dart'; 9 import 'package:analysis_server/src/analysis_logger.dart';
10 import 'package:analysis_server/src/channel.dart'; 10 import 'package:analysis_server/src/channel.dart';
11 import 'package:analysis_server/src/constants.dart'; 11 import 'package:analysis_server/src/constants.dart';
12 import 'package:analysis_server/src/context_directory_manager.dart'; 12 import 'package:analysis_server/src/context_directory_manager.dart';
13 import 'package:analysis_server/src/domain_analysis.dart'; 13 import 'package:analysis_server/src/domain_analysis.dart';
14 import 'package:analysis_server/src/operation/operation.dart';
15 import 'package:analysis_server/src/operation/operation_queue.dart';
14 import 'package:analysis_server/src/protocol.dart'; 16 import 'package:analysis_server/src/protocol.dart';
15 import 'package:analysis_server/src/resource.dart'; 17 import 'package:analysis_server/src/resource.dart';
16 import 'package:analyzer/src/generated/ast.dart'; 18 import 'package:analyzer/src/generated/ast.dart';
17 import 'package:analyzer/src/generated/engine.dart'; 19 import 'package:analyzer/src/generated/engine.dart';
18 import 'package:analyzer/src/generated/error.dart'; 20 import 'package:analyzer/src/generated/error.dart';
19 import 'package:analyzer/src/generated/java_core.dart'; 21 import 'package:analyzer/src/generated/java_core.dart';
20 import 'package:analyzer/src/generated/source.dart'; 22 import 'package:analyzer/src/generated/source.dart';
21 import 'package:analyzer/src/generated/sdk.dart'; 23 import 'package:analyzer/src/generated/sdk.dart';
22 import 'package:analyzer/src/generated/sdk_io.dart'; 24 import 'package:analyzer/src/generated/sdk_io.dart';
23 import 'package:analyzer/src/generated/source_io.dart'; 25 import 'package:analyzer/src/generated/source_io.dart';
24 import 'package:analysis_server/src/computers.dart'; 26 import 'package:analysis_server/src/computers.dart';
25 27
26 28
27 /** 29 /**
28 * An instance of [DirectoryBasedDartSdk] that is shared between 30 * An instance of [DirectoryBasedDartSdk] that is shared between
29 * [AnalysisServer] instances to improve performance. 31 * [AnalysisServer] instances to improve performance.
30 */ 32 */
31 final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk; 33 final DirectoryBasedDartSdk SHARED_SDK = DirectoryBasedDartSdk.defaultSdk;
32 34
33 class AnalysisServerContextDirectoryManager extends ContextDirectoryManager { 35 class AnalysisServerContextDirectoryManager extends ContextDirectoryManager {
34 final AnalysisServer analysisServer; 36 final AnalysisServer analysisServer;
35 37
36 AnalysisServerContextDirectoryManager(this.analysisServer, ResourceProvider re sourceProvider) 38 AnalysisServerContextDirectoryManager(this.analysisServer, ResourceProvider re sourceProvider)
37 : super(resourceProvider); 39 : super(resourceProvider);
38 40
39 void addContext(Folder folder, File pubspecFile) { 41 void addContext(Folder folder, File pubspecFile) {
40 ContextDirectory contextDirectory = new ContextDirectory( 42 ContextDirectory contextDirectory = new ContextDirectory(
41 analysisServer.defaultSdk, folder, pubspecFile); 43 analysisServer.defaultSdk, folder, pubspecFile);
42 analysisServer.folderMap[folder] = contextDirectory; 44 analysisServer.folderMap[folder] = contextDirectory;
43 analysisServer.addContextToWorkQueue(contextDirectory.context); 45 analysisServer.schedulePerformAnalysisOperation(contextDirectory.context, fa lse);
44 } 46 }
45 47
46 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) { 48 void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
47 analysisServer.folderMap[contextFolder].context.applyChanges(changeSet); 49 analysisServer.folderMap[contextFolder].context.applyChanges(changeSet);
48 } 50 }
49 } 51 }
50 52
51 /** 53 /**
52 * Instances of the class [AnalysisServer] implement a server that listens on a 54 * Instances of the class [AnalysisServer] implement a server that listens on a
53 * [CommunicationChannel] for analysis requests and process them. 55 * [CommunicationChannel] for analysis requests and process them.
(...skipping 17 matching lines...) Expand all
71 * discard any tasks it finds on [contextWorkQueue]. 73 * discard any tasks it finds on [contextWorkQueue].
72 */ 74 */
73 bool running; 75 bool running;
74 76
75 /** 77 /**
76 * A list of the request handlers used to handle the requests sent to this 78 * A list of the request handlers used to handle the requests sent to this
77 * server. 79 * server.
78 */ 80 */
79 List<RequestHandler> handlers; 81 List<RequestHandler> handlers;
80 82
81 // TODO(scheglov) remove once setAnalysisRoots() is completely implemented
82 // /**
83 // * A table mapping context id's to the analysis contexts associated with the m.
84 // */
85 // final Map<String, AnalysisContext> contextMap = new Map<String, AnalysisCont ext>();
86 //
87 // /**
88 // * A table mapping analysis contexts to the context id's associated with the m.
89 // */
90 // final Map<AnalysisContext, String> contextIdMap = new Map<AnalysisContext, S tring>();
91
92 /** 83 /**
93 * The current default [DartSdk]. 84 * The current default [DartSdk].
94 */ 85 */
95 DartSdk defaultSdk = SHARED_SDK; 86 DartSdk defaultSdk = SHARED_SDK;
96 87
97 /** 88 /**
98 * A table mapping [Folder]s to the [ContextDirectory]s associated with them. 89 * A table mapping [Folder]s to the [ContextDirectory]s associated with them.
99 */ 90 */
100 final Map<Folder, ContextDirectory> folderMap = <Folder, ContextDirectory>{}; 91 final Map<Folder, ContextDirectory> folderMap = <Folder, ContextDirectory>{};
101 92
102 /** 93 /**
103 * The context identifier used in the last status notification. 94 * The context identifier used in the last status notification.
104 */ 95 */
105 String lastStatusNotificationContextId = null; 96 String lastStatusNotificationContextId = null;
106 97
107 /** 98 final ServerOperationQueue operationQueue = new ServerOperationQueue();
108 * A list of the analysis contexts for which analysis work needs to be
109 * performed.
110 *
111 * Invariant: when this list is non-empty, there is exactly one pending call
Paul Berry 2014/06/02 16:04:41 Why is this comment being deleted? Is your intent
scheglov 2014/06/02 17:56:59 Restored for the operation queue field.
112 * to [performTask] on the event queue. When this list is empty, there are
113 * no calls to [performTask] on the event queue.
114 */
115 final List<AnalysisContext> contextWorkQueue = new List<AnalysisContext>();
116 99
117 /** 100 /**
118 * A set of the [ServerService]s to send notifications for. 101 * A set of the [ServerService]s to send notifications for.
119 */ 102 */
120 Set<ServerService> serverServices = new Set<ServerService>(); 103 Set<ServerService> serverServices = new Set<ServerService>();
121 104
122 /** 105 /**
123 * A table mapping [AnalysisService]s to the file paths for which these 106 * A table mapping [AnalysisService]s to the file paths for which these
124 * notifications should be sent. 107 * notifications should be sent.
125 */ 108 */
126 Map<AnalysisService, Set<String>> analysisServices = <AnalysisService, Set<Str ing>>{}; 109 Map<AnalysisService, Set<String>> analysisServices = <AnalysisService, Set<Str ing>>{};
127 110
128 /** 111 /**
129 * Initialize a newly created server to receive requests from and send 112 * Initialize a newly created server to receive requests from and send
130 * responses to the given [channel]. 113 * responses to the given [channel].
131 */ 114 */
132 AnalysisServer(this.channel, ResourceProvider resourceProvider) { 115 AnalysisServer(this.channel, ResourceProvider resourceProvider) {
133 contextDirectoryManager = new AnalysisServerContextDirectoryManager(this, re sourceProvider); 116 contextDirectoryManager = new AnalysisServerContextDirectoryManager(this, re sourceProvider);
134 AnalysisEngine.instance.logger = new AnalysisLogger(); 117 AnalysisEngine.instance.logger = new AnalysisLogger();
135 running = true; 118 running = true;
136 Notification notification = new Notification(NOTIFICATION_CONNECTED); 119 Notification notification = new Notification(NOTIFICATION_CONNECTED);
137 channel.sendNotification(notification); 120 channel.sendNotification(notification);
138 channel.listen(handleRequest, onDone: done, onError: error); 121 channel.listen(handleRequest, onDone: done, onError: error);
139 } 122 }
140 123
141 /** 124 /**
142 * If [running] is true, add the given [context] to the list of analysis 125 * Schedules analysis of the given context.
143 * contexts for which analysis work needs to be performed, and ensure that 126 *
144 * the work will be performed. 127 * [isContinue] is `true` if the new operation is continuation of analysis of
128 * the same context which was analyzed before.
145 */ 129 */
146 void addContextToWorkQueue(AnalysisContext context) { 130 void schedulePerformAnalysisOperation(AnalysisContext context, bool isContinue ) {
147 if (!running) { 131 // bool isPriority = priorityContexts.contains(contextId);
148 return; 132 // TODO(scheglov) support for priority sources
149 } 133 bool isPriority = false;
150 if (!contextWorkQueue.contains(context)) { 134 operationQueue.add(new PerformAnalysisOperation(context, isPriority, isConti nue));
151 contextWorkQueue.add(context); 135 _scheduleTask();
Brian Wilkerson 2014/06/02 14:32:18 I believe that this will cause the event queue to
Paul Berry 2014/06/02 16:04:41 I'm not sure we even need a closure. I think it i
152 if (contextWorkQueue.length == 1) {
153 // Work queue was previously empty, so schedule analysis.
154 _scheduleTask();
155 }
156 }
157 } 136 }
158 137
159 /** 138 /**
160 * The socket from which requests are being read has been closed. 139 * The socket from which requests are being read has been closed.
161 */ 140 */
162 void done() { 141 void done() {
163 running = false; 142 running = false;
164 } 143 }
165 144
166 /** 145 /**
(...skipping 18 matching lines...) Expand all
185 } 164 }
186 } on RequestFailure catch (exception) { 165 } on RequestFailure catch (exception) {
187 channel.sendResponse(exception.response); 166 channel.sendResponse(exception.response);
188 return; 167 return;
189 } 168 }
190 } 169 }
191 channel.sendResponse(new Response.unknownRequest(request)); 170 channel.sendResponse(new Response.unknownRequest(request));
192 } 171 }
193 172
194 /** 173 /**
195 * Perform the next available task. If a request was received that has not yet 174 * Perform the next available [ServerOperation].
196 * been performed, perform it next. Otherwise, look for some analysis that
197 * needs to be done and do that. Otherwise, do nothing.
198 */ 175 */
199 void performTask() { 176 void performTask() {
200 if (!running) { 177 if (!running) {
201 // An error has occurred, or the connection to the client has been
202 // closed, since performTask() was scheduled on the event queue. So
203 // don't do any analysis. Instead clear the work queue.
204 contextWorkQueue.clear();
Paul Berry 2014/06/02 16:04:41 Why are we getting rid of this code? Was it incor
scheglov 2014/06/02 17:56:59 Restored.
205 }
206 if (contextWorkQueue.isEmpty) {
207 // Nothing to do.
208 return; 178 return;
209 } 179 }
210 // 180 // prepare next operation
211 // Look for a context that has work to be done and then perform one task. 181 ServerOperation operation = operationQueue.take();
212 // 182 if (operation == null) {
213 List<ChangeNotice> notices = null; 183 return;
214 // String contextId; 184 }
185 // perform the operation
215 try { 186 try {
216 AnalysisContext context = contextWorkQueue[0]; 187 operation.perform(this);
217 // contextId = contextIdMap[context]; 188 } catch (e) {
218 // TODO(danrubel): Replace with context identifier or similar 189 // TODO(scheglov) decide how to handle exceptions
219 sendStatusNotification(context.toString());
220 AnalysisResult result = context.performAnalysisTask();
221 notices = result.changeNotices;
222 } finally {
Paul Berry 2014/06/02 16:04:41 Why are we dropping this logic? I believe that sc
scheglov 2014/06/02 17:56:59 Restored in performTask/performOperation.
223 if (notices == null) {
224 // Either we have no more work to do for this context, or there was an
225 // unhandled exception trying to perform the analysis. In either case,
226 // remove the context form the work queue so we won't try to do more
227 // analysis on it.
228 contextWorkQueue.removeAt(0);
229 }
230 //
231 // Schedule this method to be run again if there is any more work to be
232 // done.
233 //
234 if (!contextWorkQueue.isEmpty) {
235 _scheduleTask();
236 }
237 } 190 }
191 // schedule this method again
192 _scheduleTask();
Brian Wilkerson 2014/06/02 14:32:18 This method should only get scheduled if the queue
scheglov 2014/06/02 17:56:59 Done.
193 }
194
195 /**
196 * Perform analysis in the given [AnalysisContext].
197 */
198 void internalPerformAnalysis(AnalysisContext context) {
Brian Wilkerson 2014/06/02 14:32:18 I would prefer a style in which the code to perfor
scheglov 2014/06/02 17:56:59 Me too, but I'm afraid we have to expose too much
Brian Wilkerson 2014/06/02 18:21:03 I'd like to start with doing it the better way unt
199 // prepare results
200 AnalysisResult result = context.performAnalysisTask();
201 List<ChangeNotice> notices = result.changeNotices;
202 if (notices == null) {
203 return;
204 }
205 // TODO(scheglov) remember known sources
206 // TODO(scheglov) index units
207 // TODO(scheglov) schedule notifications
238 if (notices != null) { 208 if (notices != null) {
239 sendNotices(notices); 209 sendNotices(notices);
240 } else { 210 } else {
241 sendStatusNotification(null); 211 sendStatusNotification(null);
242 } 212 }
213 // schedule analysis again
214 schedulePerformAnalysisOperation(context, true);
Brian Wilkerson 2014/06/02 14:32:18 We need to take the "continuation" flag into accou
scheglov 2014/06/02 17:56:59 We do use it - PerformAnalysisOperation returns di
Brian Wilkerson 2014/06/02 18:21:03 I meant, if we are continuing analysis of a contex
scheglov 2014/06/02 18:32:25 Well, it is added to the tail of the ANALYSIS_CONT
243 } 215 }
244 216
245 /** 217 /**
246 * Send the information in the given list of notices back to the client. 218 * Send the information in the given list of notices back to the client.
247 */ 219 */
248 void sendNotices(List<ChangeNotice> notices) { 220 void sendNotices(List<ChangeNotice> notices) {
249 for (int i = 0; i < notices.length; i++) { 221 for (int i = 0; i < notices.length; i++) {
250 ChangeNotice notice = notices[i]; 222 ChangeNotice notice = notices[i];
251 Source source = notice.source; 223 Source source = notice.source;
252 CompilationUnit dartUnit = notice.compilationUnit; 224 CompilationUnit dartUnit = notice.compilationUnit;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 changes.forEach((file, change) { 306 changes.forEach((file, change) {
335 AnalysisContext analysisContext = _getAnalysisContext(file); 307 AnalysisContext analysisContext = _getAnalysisContext(file);
336 if (analysisContext != null) { 308 if (analysisContext != null) {
337 Source source = _getSource(file); 309 Source source = _getSource(file);
338 if (change.offset == null) { 310 if (change.offset == null) {
339 analysisContext.setContents(source, change.content); 311 analysisContext.setContents(source, change.content);
340 } else { 312 } else {
341 analysisContext.setChangedContents(source, change.content, 313 analysisContext.setChangedContents(source, change.content,
342 change.offset, change.oldLength, change.newLength); 314 change.offset, change.oldLength, change.newLength);
343 } 315 }
344 addContextToWorkQueue(analysisContext); 316 schedulePerformAnalysisOperation(analysisContext, false);
345 } 317 }
346 }); 318 });
347 } 319 }
348 320
349 /** 321 /**
350 * Implementation for `analysis.setSubscriptions`. 322 * Implementation for `analysis.setSubscriptions`.
351 */ 323 */
352 void setAnalysisSubscriptions(Map<AnalysisService, Set<String>> subscriptions) { 324 void setAnalysisSubscriptions(Map<AnalysisService, Set<String>> subscriptions) {
353 // send notifications for already analyzed sources 325 // send notifications for already analyzed sources
354 subscriptions.forEach((service, Set<String> newFiles) { 326 subscriptions.forEach((service, Set<String> newFiles) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 return null; 383 return null;
412 } 384 }
413 // get a resolved unit 385 // get a resolved unit
414 return context.getResolvedCompilationUnit2(unitSource, librarySources[0]); 386 return context.getResolvedCompilationUnit2(unitSource, librarySources[0]);
415 } 387 }
416 388
417 /** 389 /**
418 * Return `true` if all tasks are finished in this [AnalysisServer]. 390 * Return `true` if all tasks are finished in this [AnalysisServer].
419 */ 391 */
420 bool test_areTasksFinished() { 392 bool test_areTasksFinished() {
421 return contextWorkQueue.isEmpty; 393 return operationQueue.isEmpty;
422 } 394 }
423 395
424 static Map<String, Object> errorToJson(AnalysisError analysisError) { 396 static Map<String, Object> errorToJson(AnalysisError analysisError) {
425 // TODO(paulberry): move this function into the AnalysisError class. 397 // TODO(paulberry): move this function into the AnalysisError class.
426 ErrorCode errorCode = analysisError.errorCode; 398 ErrorCode errorCode = analysisError.errorCode;
427 Map<String, Object> result = { 399 Map<String, Object> result = {
428 'file': analysisError.source.fullName, 400 'file': analysisError.source.fullName,
429 // TODO(scheglov) add Enum.fullName ? 401 // TODO(scheglov) add Enum.fullName ?
430 'errorCode': '${errorCode.runtimeType}.${(errorCode as Enum).name}', 402 'errorCode': '${errorCode.runtimeType}.${(errorCode as Enum).name}',
431 'offset': analysisError.offset, 403 'offset': analysisError.offset,
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 /** 488 /**
517 * An enumeration of the services provided by the server domain. 489 * An enumeration of the services provided by the server domain.
518 */ 490 */
519 class ServerService extends Enum2<ServerService> { 491 class ServerService extends Enum2<ServerService> {
520 static const ServerService STATUS = const ServerService('STATUS', 0); 492 static const ServerService STATUS = const ServerService('STATUS', 0);
521 493
522 static const List<ServerService> VALUES = const [STATUS]; 494 static const List<ServerService> VALUES = const [STATUS];
523 495
524 const ServerService(String name, int ordinal) : super(name, ordinal); 496 const ServerService(String name, int ordinal) : super(name, ordinal);
525 } 497 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analysis_server/lib/src/domain_context.dart » ('j') | pkg/analysis_server/lib/src/operation/operation.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698