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

Side by Side Diff: pkg/barback/lib/src/transform_node.dart

Issue 243103003: Run declaring transformers eagerly if possible, even if their inputs are deferred. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 barback.transform_node; 5 library barback.transform_node;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 8
9 import 'asset.dart'; 9 import 'asset.dart';
10 import 'asset_id.dart'; 10 import 'asset_id.dart';
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 bool get isDirty => _state != _State.NOT_PRIMARY && 48 bool get isDirty => _state != _State.NOT_PRIMARY &&
49 _state != _State.APPLIED && _state != _State.DECLARED; 49 _state != _State.APPLIED && _state != _State.DECLARED;
50 50
51 /// Whether this transform is deferred. 51 /// Whether this transform is deferred.
52 /// 52 ///
53 /// A transform is deferred if either its transformer is lazy or if its 53 /// A transform is deferred if either its transformer is lazy or if its
54 /// transformer is declaring and its primary input comes from a deferred 54 /// transformer is declaring and its primary input comes from a deferred
55 /// transformer. 55 /// transformer.
56 final bool deferred; 56 final bool deferred;
57 57
58 /// Whether this is a deferred transform waiting for [force] to be called to 58 /// Whether this transform has been forced since it last finished applying.
59 /// generate inputs.
60 /// 59 ///
61 /// This defaults to `true` for deferred transforms and `false` otherwise. 60 /// A transform being forced means it should run until it generates outputs
62 /// During or after running `isPrimary` or `declareOutputs`, this may become 61 /// and is no longer dirty. This is always true for non-[deferred]
63 /// `false`, indicating that the transform has been forced and should generate 62 /// transformers, since they always need to eagerly generate outputs.
64 /// outputs as soon as possible. It will only be set back to `true` if an 63 bool _forced;
65 /// input changes *after* `apply` has completed.
66 bool _awaitingForce;
67 64
68 /// The subscriptions to each input's [AssetNode.onStateChange] stream. 65 /// The subscriptions to each input's [AssetNode.onStateChange] stream.
69 final _inputSubscriptions = new Map<AssetId, StreamSubscription>(); 66 final _inputSubscriptions = new Map<AssetId, StreamSubscription>();
70 67
71 /// The controllers for the asset nodes emitted by this node. 68 /// The controllers for the asset nodes emitted by this node.
72 final _outputControllers = new Map<AssetId, AssetNodeController>(); 69 final _outputControllers = new Map<AssetId, AssetNodeController>();
73 70
74 /// The ids of inputs the transformer tried and failed to read last time it 71 /// The ids of inputs the transformer tried and failed to read last time it
75 /// ran. 72 /// ran.
76 final _missingInputs = new Set<AssetId>(); 73 final _missingInputs = new Set<AssetId>();
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its 125 /// This is only non-null if [transformer] is a [DeclaringTransformer] and its
129 /// [declareOutputs] has been run successfully. 126 /// [declareOutputs] has been run successfully.
130 Set<AssetId> _declaredOutputs; 127 Set<AssetId> _declaredOutputs;
131 128
132 TransformNode(this.phase, Transformer transformer, AssetNode primary, 129 TransformNode(this.phase, Transformer transformer, AssetNode primary,
133 this._location) 130 this._location)
134 : transformer = transformer, 131 : transformer = transformer,
135 primary = primary, 132 primary = primary,
136 deferred = transformer is LazyTransformer || 133 deferred = transformer is LazyTransformer ||
137 (transformer is DeclaringTransformer && primary.deferred) { 134 (transformer is DeclaringTransformer && primary.deferred) {
138 _awaitingForce = deferred; 135 _forced = !deferred;
139 136
140 _onLogPool.add(_onLogController.stream); 137 _onLogPool.add(_onLogController.stream);
141 138
142 _primarySubscription = primary.onStateChange.listen((state) { 139 _primarySubscription = primary.onStateChange.listen((state) {
143 if (state.isRemoved) { 140 if (state.isRemoved) {
144 remove(); 141 remove();
145 } else { 142 } else {
146 if (state.isDirty && !deferred) primary.force(); 143 if (state.isDirty && !deferred) primary.force();
147 // If this is deferred but applying, that means it must have been 144 // If this is deferred but applying, that means it must have been
148 // forced, so we should ensure its input remains forced as well. 145 // forced, so we should ensure its input remains forced as well.
149 if (deferred && _state == _State.APPLYING) primary.force(); 146 if (deferred && _forced && _state == _State.APPLYING) primary.force();
150 _dirty(); 147 _dirty();
151 } 148 }
152 }); 149 });
153 150
154 _phaseSubscription = phase.previous.onAsset.listen((node) { 151 _phaseSubscription = phase.previous.onAsset.listen((node) {
155 if (!_missingInputs.contains(node.id)) return; 152 if (!_missingInputs.contains(node.id)) return;
156 if (!deferred) node.force(); 153 if (!deferred) node.force();
157 _dirty(); 154 _dirty();
158 }); 155 });
159 156
(...skipping 22 matching lines...) Expand all
182 _clearOutputs(); 179 _clearOutputs();
183 if (_passThroughController != null) { 180 if (_passThroughController != null) {
184 _passThroughController.setRemoved(); 181 _passThroughController.setRemoved();
185 _passThroughController = null; 182 _passThroughController = null;
186 } 183 }
187 } 184 }
188 185
189 /// If [this] is deferred, ensures that its concrete outputs will be 186 /// If [this] is deferred, ensures that its concrete outputs will be
190 /// generated. 187 /// generated.
191 void force() { 188 void force() {
192 if (!_awaitingForce) return; 189 if (_forced || _state == _State.APPLIED) return;
193 primary.force(); 190 primary.force();
194 _awaitingForce = false; 191 _forced = true;
195 _dirty(); 192 _dirty();
196 } 193 }
197 194
198 /// Marks this transform as dirty. 195 /// Marks this transform as dirty.
199 /// 196 ///
200 /// This causes all of the transform's outputs to be marked as dirty as well. 197 /// This causes all of the transform's outputs to be marked as dirty as well.
201 void _dirty() { 198 void _dirty() {
202 if (_state == _State.NOT_PRIMARY) { 199 if (_state == _State.NOT_PRIMARY) {
203 _emitPassThrough(); 200 _emitPassThrough();
204 return; 201 return;
205 } 202 }
206 203
207 // If we're in the process of running [isPrimary] or [declareOutputs], we 204 // If we're in the process of running [isPrimary] or [declareOutputs], we
208 // already know that [apply] needs to be run so there's nothing we need to 205 // already know that [apply] needs to be run so there's nothing we need to
209 // mark as dirty. 206 // mark as dirty.
210 if (_state == _State.DECLARING) return; 207 if (_state == _State.DECLARING) return;
211 208
212 // If we're waiting until [force] is called to run [apply], we don't want to 209 if (!_forced &&
213 // run [apply] too early. 210 // If [transformer] is declaring and [primary] is available, we do want
214 if (_awaitingForce) return; 211 // to start running [apply] even if [force] hasn't been called, since
212 // [transformer] should run eagerly if possible.
213 (transformer is LazyTransformer || !primary.state.isAvailable)) {
Bob Nystrom 2014/04/21 22:37:40 This condition is pretty dense. How about breaking
nweiz 2014/04/21 22:52:09 Done.
214 // [forced] should only ever be false for a deferred transform.
215 assert(deferred);
215 216
216 if (_state == _State.APPLIED && deferred) { 217 // If we've finished applying, transition to DECLARED, indicating that we
217 // Transition to DECLARED, indicating that we know what outputs [apply] 218 // know what outputs [apply] will emit but we're waiting to emit them
218 // will emit but we're waiting to emit them concretely until [force] is 219 // concretely until [force] is called. If we're still applying, we'll
219 // called. 220 // transition to DECLARED once we finish.
220 _state = _State.DECLARED; 221 if (_state == _State.APPLIED) _state = _State.DECLARED;
221 _awaitingForce = true;
222 for (var controller in _outputControllers.values) { 222 for (var controller in _outputControllers.values) {
223 controller.setLazy(force); 223 controller.setLazy(force);
224 } 224 }
225 return; 225 return;
226 } 226 }
227 227
228 if (_passThroughController != null) _passThroughController.setDirty(); 228 if (_passThroughController != null) _passThroughController.setDirty();
229 for (var controller in _outputControllers.values) { 229 for (var controller in _outputControllers.values) {
230 controller.setDirty(); 230 controller.setDirty();
231 } 231 }
(...skipping 18 matching lines...) Expand all
250 // is so a broken transformer doesn't take down the whole graph. 250 // is so a broken transformer doesn't take down the whole graph.
251 phase.cascade.reportError(_wrapException(error, stackTrace)); 251 phase.cascade.reportError(_wrapException(error, stackTrace));
252 252
253 return false; 253 return false;
254 }).then((isPrimary) { 254 }).then((isPrimary) {
255 if (_isRemoved) return null; 255 if (_isRemoved) return null;
256 if (isPrimary) { 256 if (isPrimary) {
257 if (!deferred) primary.force(); 257 if (!deferred) primary.force();
258 return _declareOutputs().then((_) { 258 return _declareOutputs().then((_) {
259 if (_isRemoved) return; 259 if (_isRemoved) return;
260 if (_awaitingForce) { 260 if (_forced) {
261 _apply();
262 } else {
261 _state = _State.DECLARED; 263 _state = _State.DECLARED;
262 _onDoneController.add(null); 264 _onDoneController.add(null);
263 } else {
264 _apply();
265 } 265 }
266 }); 266 });
267 } 267 }
268 268
269 _emitPassThrough(); 269 _emitPassThrough();
270 _state = _State.NOT_PRIMARY; 270 _state = _State.NOT_PRIMARY;
271 _onDoneController.add(null); 271 _onDoneController.add(null);
272 }); 272 });
273 } 273 }
274 274
(...skipping 16 matching lines...) Expand all
291 .where((id) => id.package != phase.cascade.package).toSet(); 291 .where((id) => id.package != phase.cascade.package).toSet();
292 for (var id in invalidIds) { 292 for (var id in invalidIds) {
293 _declaredOutputs.remove(id); 293 _declaredOutputs.remove(id);
294 // TODO(nweiz): report this as a warning rather than a failing error. 294 // TODO(nweiz): report this as a warning rather than a failing error.
295 phase.cascade.reportError(new InvalidOutputException(info, id)); 295 phase.cascade.reportError(new InvalidOutputException(info, id));
296 } 296 }
297 297
298 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough(); 298 if (!_declaredOutputs.contains(primary.id)) _emitPassThrough();
299 299
300 for (var id in _declaredOutputs) { 300 for (var id in _declaredOutputs) {
301 var controller = _awaitingForce 301 var controller = _forced
302 ? new AssetNodeController.lazy(id, force, this) 302 ? new AssetNodeController(id, this)
303 : new AssetNodeController(id, this); 303 : new AssetNodeController.lazy(id, force, this);
304 _outputControllers[id] = controller; 304 _outputControllers[id] = controller;
305 _onAssetController.add(controller.node); 305 _onAssetController.add(controller.node);
306 } 306 }
307 }).catchError((error, stackTrace) { 307 }).catchError((error, stackTrace) {
308 if (_isRemoved) return; 308 if (_isRemoved) return;
309 phase.cascade.reportError(_wrapException(error, stackTrace)); 309 phase.cascade.reportError(_wrapException(error, stackTrace));
310 }); 310 });
311 } 311 }
312 312
313 /// Applies this transform. 313 /// Applies this transform.
314 void _apply() { 314 void _apply() {
315 assert(!_isRemoved && !_awaitingForce); 315 assert(!_isRemoved);
316 316
317 // Clear input subscriptions here as well as in [_process] because [_apply] 317 // Clear input subscriptions here as well as in [_process] because [_apply]
318 // may be restarted independently if only a secondary input changes. 318 // may be restarted independently if only a secondary input changes.
319 _clearInputSubscriptions(); 319 _clearInputSubscriptions();
320 _state = _State.APPLYING; 320 _state = _State.APPLYING;
321 _runApply().then((hadError) { 321 _runApply().then((hadError) {
322 if (_isRemoved) return; 322 if (_isRemoved) return;
323 323
324 if (_state == _State.DECLARED) return;
325
324 if (_state == _State.NEEDS_APPLY) { 326 if (_state == _State.NEEDS_APPLY) {
325 _apply(); 327 _apply();
326 return; 328 return;
327 } 329 }
328 330
331 if (deferred) _forced = false;
332
329 assert(_state == _State.APPLYING); 333 assert(_state == _State.APPLYING);
330 if (hadError) { 334 if (hadError) {
331 _clearOutputs(); 335 _clearOutputs();
332 // If the transformer threw an error, we don't want to emit the 336 // If the transformer threw an error, we don't want to emit the
333 // pass-through asset in case it will be overwritten by the transformer. 337 // pass-through asset in case it will be overwritten by the transformer.
334 // However, if the transformer declared that it wouldn't overwrite or 338 // However, if the transformer declared that it wouldn't overwrite or
335 // consume the pass-through asset, we can safely emit it. 339 // consume the pass-through asset, we can safely emit it.
336 if (_declaredOutputs != null && !_consumePrimary && 340 if (_declaredOutputs != null && !_consumePrimary &&
337 !_declaredOutputs.contains(primary.id)) { 341 !_declaredOutputs.contains(primary.id)) {
338 _emitPassThrough(); 342 _emitPassThrough();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 /// Returns whether or not an error occurred while running the transformer. 376 /// Returns whether or not an error occurred while running the transformer.
373 Future<bool> _runApply() { 377 Future<bool> _runApply() {
374 var transformController = new TransformController(this); 378 var transformController = new TransformController(this);
375 _onLogPool.add(transformController.onLog); 379 _onLogPool.add(transformController.onLog);
376 380
377 return primary.whenAvailable((_) { 381 return primary.whenAvailable((_) {
378 if (_isRemoved) return null; 382 if (_isRemoved) return null;
379 _state = _State.APPLYING; 383 _state = _State.APPLYING;
380 return syncFuture(() => transformer.apply(transformController.transform)); 384 return syncFuture(() => transformer.apply(transformController.transform));
381 }).then((_) { 385 }).then((_) {
382 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; 386 if (deferred && !_forced && !primary.state.isAvailable) {
387 _state = _State.DECLARED;
388 _onDoneController.add(null);
389 return false;
390 }
391
392 if (_isRemoved) return false;
393 if (_state == _State.NEEDS_APPLY) return false;
394 if (_state == _State.DECLARING) return false;
383 if (transformController.loggedError) return true; 395 if (transformController.loggedError) return true;
384 _handleApplyResults(transformController); 396 _handleApplyResults(transformController);
385 return false; 397 return false;
386 }).catchError((error, stackTrace) { 398 }).catchError((error, stackTrace) {
387 // If the transform became dirty while processing, ignore any errors from 399 // If the transform became dirty while processing, ignore any errors from
388 // it. 400 // it.
389 if (_state == _State.NEEDS_APPLY || _isRemoved) return false; 401 if (_state == _State.NEEDS_APPLY || _isRemoved) return false;
390 402
391 // Catch all transformer errors and pipe them to the results stream. This 403 // Catch all transformer errors and pipe them to the results stream. This
392 // is so a broken transformer doesn't take down the whole graph. 404 // is so a broken transformer doesn't take down the whole graph.
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 /// 561 ///
550 /// This will never transition to another state. 562 /// This will never transition to another state.
551 static final NOT_PRIMARY = const _State._("not primary"); 563 static final NOT_PRIMARY = const _State._("not primary");
552 564
553 final String name; 565 final String name;
554 566
555 const _State._(this.name); 567 const _State._(this.name);
556 568
557 String toString() => name; 569 String toString() => name;
558 } 570 }
OLDNEW
« no previous file with comments | « pkg/barback/CHANGELOG.md ('k') | pkg/barback/test/package_graph/declaring_transformer_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698