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

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

Issue 27242002: Use file pool to handle running out of file descriptors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename test. 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
« no previous file with comments | « pkg/barback/lib/src/asset.dart ('k') | pkg/barback/test/too_many_open_files_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library barback.file_pool;
Jennifer Messerly 2013/10/14 21:00:08 barback.src.file_pool? Or did you mean to make th
Siggi Cherem (dart-lang) 2013/10/14 21:14:28 Good point. Making it visible would simplify what
Bob Nystrom 2013/10/14 21:26:13 We don't use ".src" in other library names in Barb
Bob Nystrom 2013/10/14 21:26:13 I'm trying to avoid exposing this functionality as
Jennifer Messerly 2013/10/14 21:30:42 trivial detail but: regarding library name -- shou
Bob Nystrom 2013/10/14 22:06:58 Hmm, good point. I'm up for changing all of these
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:io';
10
11 /// Manages a pool of files that are opened for reading to cope with maximum
12 /// file descriptor limits.
13 ///
14 /// If a file cannot be opened because too many files are already open, this
15 /// will defer the open until a previously opened file is closed and then try
16 /// again. If this doesn't succeed after a certain amount of time, the open
17 /// will fail and the original "too many files" exception will be thrown.
18 class FilePool {
19 // TODO(rnystrom): Should we cap this to some maximum size?
20 final _pendingListens = new Queue<_FileReader>();
21
22 /// Opens [file] for reading.
23 ///
24 /// When the returned stream is listened to, if there are too many files
25 /// open, this will wait for a previously opened to file to be closed and
26 /// then try again.
27 Stream<List<int>> openRead(File file) => new _FileReader(this, file).stream;
Siggi Cherem (dart-lang) 2013/10/14 21:14:28 if we make it public, can we also add openWrite?
Bob Nystrom 2013/10/14 21:26:13 See above. Trying to not make it public. :)
28
29 void _retryPendingListen() {
30 if (_pendingListens.isEmpty) return;
31
32 var pending = _pendingListens.removeFirst();
33 pending._listen();
34 }
35 }
36
37 /// Wraps a raw file reading stream in a stream that handles "too many files"
38 /// errors.
39 ///
40 /// This also notifies the pool when the underlying file stream is closed so
41 /// that it can try to open a waiting file.
42 class _FileReader {
43 final FilePool _pool;
44 final File _file;
45
46 /// The underyling file stream.
47 Stream<List<int>> _fileStream;
48
49 /// The controller for the wrapped stream.
50 StreamController<List<int>> _controller;
51
52 /// The current subscription to the underlying file stream.
53 ///
54 /// This will only be non-null while the wrapped stream is being listened to.
55 StreamSubscription _subscription;
56 Timer _timer;
57
58 /// When a [listen] call has thrown a "too many files" error, this will be
59 /// the exception object.
60 Object _exception;
61
62 /// When a [listen] call has thrown a "too many files" error, this will be
63 /// the captured stack trace.
64 Object _stackTrace;
65
66 /// The wrapped stream that the file can be read from.
67 Stream<List<int>> get stream {
68 if (_controller != null) return _controller.stream;
69
70 _controller = new StreamController<List<int>>(onListen: _listen,
71 onPause: () {
72 _subscription.pause();
73 }, onResume: () {
74 _subscription.resume();
75 }, onCancel: () {
76 if (_subscription != null) _subscription.cancel();
77 _subscription = null;
78 }, sync: true);
79
80 return _controller.stream;
81 }
82
83 _FileReader(this._pool, this._file);
84
85 /// Starts listening to the underlying file stream.
86 void _listen() {
87 if (_timer != null) {
88 _timer.cancel();
89 _timer = null;
90 }
91
92 _fileStream = _file.openRead();
93 _subscription = _fileStream.listen(_controller.add,
94 onError: _onError, onDone: _onDone, cancelOnError: true);
95 }
96
97 /// Handles an error from the underlying file stream.
98 ///
99 /// "Too many file" errors are caught so that we can retry later. Other
100 /// errors are passed to the wrapped stream and the underlying stream
101 /// subscription is canceled.
102 void _onError(Object exception, Object stackTrace) {
103 assert(_subscription != null);
104 assert(_exception == null);
105
106 // The subscription is canceled after an error.
107 _subscription = null;
108
109 // We only handle "Too many open files errors".
110 if (exception is! FileException || exception.osError.errorCode != 24) {
111 // TODO(bob): stack trace.
112 _controller.addError(exception, stackTrace);
113 return;
114 }
115
116 // TODO(bob): What if already deferred?
117 _exception = exception;
118 _stackTrace = stackTrace;
119
120 // We'll try to defer the listen in the hopes that another file will close
121 // and we can try. If that doesn't happen after a while, give up and just
122 // throw the original error.
123 // TODO(bob): How long?
124 _timer = new Timer(new Duration(seconds: 5), _onTimeout);
125
126 // Tell the pool that this file is waiting.
127 _pool._pendingListens.add(this);
128 }
129
130 /// Handles the underlying file stream finishing.
131 void _onDone() {
132 _subscription = null;
133
134 _controller.close();
135 _pool._retryPendingListen();
136 }
137
138 /// If this file failed to be read because there were too many open files and
139 /// no file was closed in time to retry, this handles giving up.
140 void _onTimeout() {
141 assert(_subscription == null);
142 assert(_exception != null);
143
144 // We failed to open in time, so just fail with the original error.
145 _pool._pendingListens.remove(this);
146 _controller.addError(_exception, _stackTrace);
147 _controller.close();
148
149 _timer = null;
150 _exception = null;
151 _stackTrace = null;
152
153 }
154 }
OLDNEW
« no previous file with comments | « pkg/barback/lib/src/asset.dart ('k') | pkg/barback/test/too_many_open_files_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698