@@ -168,14 +168,61 @@ class ToolDefinition {
168
168
}
169
169
}
170
170
171
+ /// Manages the creation of a single snapshot file in a context where multiple
172
+ /// async functions could be trying to use and/or create it.
173
+ ///
174
+ /// To use:
175
+ ///
176
+ /// var s = new Snapshot(...);
177
+ ///
178
+ /// if (s.needsSnapshot) {
179
+ /// // create s.snapshotFile, then call:
180
+ /// s.snapshotCompleted();
181
+ /// } else {
182
+ /// await snapshotValid();
183
+ /// // use existing s.snapshotFile;
184
+ /// }
185
+ ///
186
+ class Snapshot {
187
+ File _snapshotFile;
188
+ File get snapshotFile => _snapshotFile;
189
+ final Completer _snapshotCompleter = Completer ();
190
+
191
+ Snapshot (Directory snapshotCache, String toolPath, int serial) {
192
+ if (toolPath.endsWith ('.snapshot' )) {
193
+ _needsSnapshot = false ;
194
+ _snapshotFile = File (toolPath);
195
+ snapshotCompleted ();
196
+ } else {
197
+ _snapshotFile =
198
+ File (pathLib.join (snapshotCache.absolute.path, 'snapshot_$serial ' ));
199
+ }
200
+ }
201
+
202
+ bool _needsSnapshot = true ;
203
+
204
+ /// Will return true precisely once, unless [toolPath] was already a snapshot.
205
+ /// In that case, will always return false.
206
+ bool get needsSnapshot {
207
+ if (_needsSnapshot == true ) {
208
+ _needsSnapshot = false ;
209
+ return true ;
210
+ }
211
+ return _needsSnapshot;
212
+ }
213
+
214
+ Future <void > snapshotValid () => _snapshotCompleter.future;
215
+ void snapshotCompleted () => _snapshotCompleter.complete ();
216
+ }
217
+
171
218
/// A singleton that keeps track of cached snapshot files. The [dispose]
172
219
/// function must be called before process exit to clean up snapshots in the
173
220
/// cache.
174
221
class SnapshotCache {
175
222
static SnapshotCache _instance;
176
223
177
224
Directory snapshotCache;
178
- final Map <String , File > snapshots = {};
225
+ final Map <String , Snapshot > snapshots = {};
179
226
int _serial = 0 ;
180
227
181
228
SnapshotCache ._()
@@ -187,15 +234,13 @@ class SnapshotCache {
187
234
return _instance;
188
235
}
189
236
190
- File getSnapshot (String toolPath) {
237
+ Snapshot getSnapshot (String toolPath) {
191
238
if (snapshots.containsKey (toolPath)) {
192
239
return snapshots[toolPath];
193
240
}
194
- File snapshot =
195
- File (pathLib.join (snapshotCache.absolute.path, 'snapshot_$_serial ' ));
241
+ snapshots[toolPath] = new Snapshot (snapshotCache, toolPath, _serial);
196
242
_serial++ ;
197
- snapshots[toolPath] = snapshot;
198
- return snapshot;
243
+ return snapshots[toolPath];
199
244
}
200
245
201
246
void dispose () {
@@ -217,43 +262,26 @@ class DartToolDefinition extends ToolDefinition {
217
262
assert (args[0 ] == command.first);
218
263
// Set up flags to create a new snapshot, if needed, and use the first run as the training
219
264
// run.
220
- File snapshotFile = await getSnapshotFile ();
221
- if (snapshotFile.existsSync ()) {
222
- // replace the first argument with the path to the snapshot.
223
- args[0 ] = snapshotFile.absolute.path;
224
- } else {
265
+ Snapshot snapshot = SnapshotCache .instance.getSnapshot (command.first);
266
+ File snapshotFile = snapshot.snapshotFile;
267
+ bool needsSnapshot = snapshot.needsSnapshot;
268
+ if (needsSnapshot) {
225
269
args.insertAll (0 , [
226
270
'--snapshot=${snapshotFile .absolute .path }' ,
227
271
'--snapshot_kind=app-jit'
228
272
]);
273
+ } else {
274
+ await snapshot.snapshotValid ();
275
+ // replace the first argument with the path to the snapshot.
276
+ args[0 ] = snapshotFile.absolute.path;
229
277
}
230
278
return new Tuple2 (Platform .resolvedExecutable,
231
- _snapshotCompleter.isCompleted ? null : _snapshotCompleter.complete );
279
+ needsSnapshot ? snapshot.snapshotCompleted : null );
232
280
}
233
281
234
282
DartToolDefinition (
235
283
List <String > command, List <String > setupCommand, String description)
236
- : super (command, setupCommand, description) {
237
- // If the dart tool is already a snapshot, then we just use that.
238
- if (command[0 ].endsWith ('.snapshot' )) {
239
- _snapshotPath = File (command[0 ]);
240
- _snapshotCompleter.complete ();
241
- }
242
- }
243
-
244
- final Completer _snapshotCompleter = new Completer ();
245
-
246
- /// If the tool has a pre-built snapshot, it will be stored here.
247
- File _snapshotPath;
248
-
249
- Future <File > getSnapshotFile () async {
250
- if (_snapshotPath == null ) {
251
- _snapshotPath = SnapshotCache .instance.getSnapshot (command.first);
252
- } else {
253
- await _snapshotCompleter.future;
254
- }
255
- return _snapshotPath;
256
- }
284
+ : super (command, setupCommand, description);
257
285
}
258
286
259
287
/// A configuration class that can interpret [ToolDefinition] s from a YAML map.
0 commit comments