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

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

Issue 36213002: Only run at most 10 transformers at once in barback. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Bug fixes Created 7 years, 2 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
(Empty)
1 import 'dart:async';
2 import 'dart:collection';
3
4 import 'package:stack_trace/stack_trace.dart';
5
6 /// Manages an abstract pool of resources with a limit on how many may be in use
7 /// at once.
8 ///
9 /// When a resource is needed, the user should call [checkOut]. When the
10 /// returned future completes with a [PoolResource], the resource may be
11 /// allocated. Once the resource has been released, the user should call
12 /// [PoolResource.release]. The pool will ensure that only a certain number of
13 /// [PoolResource]s may be checked out at once.
14 class Pool {
15 /// Completers for checkouts beyond the first [_maxCheckedOutResources].
16 ///
17 /// When an item is released, the next element of [_pendingResources] will be
18 /// completed.
19 final _pendingResources = new Queue<Completer<PoolResource>>();
20
21 /// The maximum number of resources that may be checked out at once.
22 final int _maxCheckedOutResources;
23
24 /// The number of resources that are currently checked out.
25 int _checkedOutResources = 0;
26
27 /// The timeout timer.
28 ///
29 /// If [_timeout] isn't null, this timer is set as soon as the resource limit
30 /// is reached and is reset every time an resource is released or a new
31 /// resource is requested. If it fires, that indicates that the caller became
32 /// deadlocked, likely due to files waiting for additional files to be read
33 /// before they could be closed.
34 Timer _timer;
35
36 /// The amount of time to wait before timing out the pending resources.
37 Duration _timeout;
38
39 /// Creates a new pool with the given limit on how many resources may be
40 /// checked out at once.
41 ///
42 /// If [timeout] is passed, then if that much time passes without any activity
43 /// all pending [checkOut] futures will throw an exception. This is indented
44 /// to avoid deadlocks.
45 Pool(this._maxCheckedOutResources, {Duration timeout})
46 : _timeout = timeout;
47
48 /// Check out a [PoolResource].
49 ///
50 /// If the maximum number of resources is already checked out, this will delay
51 /// until one of them is released.
52 Future<PoolResource> checkOut() {
Bob Nystrom 2013/10/28 17:32:21 What do you think of "acquire" for this? "checkOut
nweiz 2013/10/29 00:06:21 Done. Referring to the "acquired resources" as the
53 if (_checkedOutResources < _maxCheckedOutResources) {
54 _checkedOutResources++;
55 return new Future.value(new PoolResource._(this));
56 } else {
57 var completer = new Completer<PoolResource>();
58 _pendingResources.add(completer);
59 _heartbeat();
60 return completer.future;
61 }
62 }
63
64 /// Checks out a resource for the duration of [callback], which may return a
65 /// Future.
66 ///
67 /// The return value of [callback] is piped to the returned Future.
68 Future withResource(callback()) {
69 return checkOut().then((resource) =>
70 new Future.sync(callback).whenComplete(resource.release));
71 }
72
73 /// If there are any pending checkouts, this will fire the oldest one.
74 void _onResourceReleased() {
75 if (_pendingResources.isEmpty) {
76 _checkedOutResources--;
77 if (_timer != null) {
78 _timer.cancel();
79 _timer = null;
80 }
81 return;
82 }
83
84 _heartbeat();
85 var pending = _pendingResources.removeFirst();
86 pending.complete(new PoolResource._(this));
87 }
88
89 /// Indicates that some external action has occurred and the timer should be
Bob Nystrom 2013/10/28 17:32:21 "Indicates that some external action" -> "A resour
nweiz 2013/10/29 00:06:21 Done.
90 /// restarted.
91 void _heartbeat() {
92 if (_timer != null) _timer.cancel();
93 if (_timeout == null) {
94 _timer = null;
95 } else {
96 _timer = new Timer(_timeout, _onTimeout);
97 }
98 }
99
100 /// Handles [_timer] timing out by causing all pending resource completers to
101 /// emit exceptions.
102 void _onTimeout() {
103 for (var completer in _pendingResources) {
104 completer.completeException("Pool deadlock: all resources have been "
105 "checked out for too long.", new Trace.current().vmTrace);
106 }
107 _pendingResources.clear();
108 _timer = null;
109 }
110 }
111
112 /// A member of a [Pool].
113 ///
114 /// A [PoolResource] is a token that indicates that a resource is allocated.
115 /// When the associated resource is released, the user should call [release].
116 class PoolResource {
117 final Pool _pool;
118
119 /// Whether [this] has been released yet.
120 bool _released = false;
121
122 PoolResource._(this._pool);
123
124 /// Tells the parent [Pool] that the resource associated with this resource is
125 /// no longer allocated, and that a new [PoolResource] may be checked out.
126 void release() {
127 if (_released) {
128 throw new StateError("A PoolResource may only be released once.");
129 }
130 _released = true;
131 _pool._onResourceReleased();
132 }
133 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698