Permalink
Browse files

Merge branch 'domains3'

  • Loading branch information...
2 parents e621250 + d4ed2e6 commit 8673a4aa25c860bf819e2d2f67eafb538b7de378 @isaacs isaacs committed Apr 17, 2012
View
@@ -4,7 +4,9 @@ sudo sysctl -w net.inet.ip.portrange.first=12000
sudo sysctl -w net.inet.tcp.msl=1000
sudo sysctl -w kern.maxfiles=1000000 kern.maxfilesperproc=1000000
ulimit -n 100000
+
./node benchmark/http_simple.js || exit 1 &
sleep 1
-ab -n 30000 -c 100 http://127.0.0.1:8000/bytes/123 | grep Req
+
+ab -n 30000 -c 100 http://127.0.0.1:8000/${TYPE:-bytes}/${LENGTH:-1024} | grep Req
killall node
View
@@ -14,7 +14,27 @@ for (var i = 0; i < 20*1024; i++) {
stored = {};
storedBuffer = {};
+var useDomains = process.env.NODE_USE_DOMAINS;
+
+// set up one global domain.
+if (useDomains) {
+ var domain = require('domain');
+ var gdom = domain.create();
+ gdom.on('error', function(er) {
+ console.log('Error on global domain', er);
+ throw er;
+ });
+ gdom.enter();
+}
+
var server = http.createServer(function (req, res) {
+
+ if (useDomains) {
+ var dom = domain.create();
+ dom.add(req);
+ dom.add(res);
+ }
+
var commands = req.url.split("/");
var command = commands[1];
var body = "";
View
@@ -8,6 +8,7 @@
* [Process](process.html)
* [Utilities](util.html)
* [Events](events.html)
+* [Domain](domain.html)
* [Buffer](buffer.html)
* [Stream](stream.html)
* [Crypto](crypto.html)
View
@@ -8,6 +8,7 @@
@include process
@include util
@include events
+@include domain
@include buffer
@include stream
@include crypto
View
@@ -0,0 +1,181 @@
+# Domain
+
+ Stability: 1 - Experimental
+
+Domains provide a way to handle multiple different IO operations as a
+single group. If any of the event emitters or callbacks registered to a
+domain emit an `error` event, or throw an error, then the domain object
+will be notified, rather than losing the context of the error in the
+`process.on('uncaughtException')` handler, or causing the program to
+exit with an error code.
+
+This feature is new in Node version 0.8. It is a first pass, and is
+expected to change significantly in future versions. Please use it and
+provide feedback.
+
+Due to their experimental nature, the Domains features are disabled unless
+the `domain` module is loaded at least once. No domains are created or
+registered by default. This is by design, to prevent adverse effects on
+current programs. It is expected to be enabled by default in future
+Node.js versions.
+
+## Additions to Error objects
+
+<!-- type=misc -->
+
+Any time an Error object is routed through a domain, a few extra fields
+are added to it.
+
+* `error.domain` The domain that first handled the error.
+* `error.domain_emitter` The event emitter that emitted an 'error' event
+ with the error object.
+* `error.domain_bound` The callback function which was bound to the
+ domain, and passed an error as its first argument.
+* `error.domain_thrown` A boolean indicating whether the error was
+ thrown, emitted, or passed to a bound callback function.
+
+## Implicit Binding
+
+<!--type=misc-->
+
+If domains are in use, then all new EventEmitter objects (including
+Stream objects, requests, responses, etc.) will be implicitly bound to
+the active domain at the time of their creation.
+
+Additionally, callbacks passed to lowlevel event loop requests (such as
+to fs.open, or other callback-taking methods) will automatically be
+bound to the active domain. If they throw, then the domain will catch
+the error.
+
+In order to prevent excessive memory usage, Domain objects themselves
+are not implicitly added as children of the active domain. If they
+were, then it would be too easy to prevent request and response objects
+from being properly garbage collected.
+
+If you *want* to nest Domain objects as children of a parent Domain,
+then you must explicitly add them, and then dispose of them later.
+
+Implicit binding routes thrown errors and `'error'` events to the
+Domain's `error` event, but does not register the EventEmitter on the
+Domain, so `domain.dispose()` will not shut down the EventEmitter.
+Implicit binding only takes care of thrown errors and `'error'` events.
+
+## domain.create()
+
+* return: {Domain}
+
+Returns a new Domain object.
+
+## Class: Domain
+
+The Domain class encapsulates the functionality of routing errors and
+uncaught exceptions to the active Domain object.
+
+Domain is a child class of EventEmitter. To handle the errors that it
+catches, listen to its `error` event.
+
+### domain.members
+
+* {Array}
+
+An array of timers and event emitters that have been explicitly added
+to the domain.
+
+### domain.add(emitter)
+
+* `emitter` {EventEmitter | Timer} emitter or timer to be added to the domain
+
+Explicitly adds an emitter to the domain. If any event handlers called by
+the emitter throw an error, or if the emitter emits an `error` event, it
+will be routed to the domain's `error` event, just like with implicit
+binding.
+
+This also works with timers that are returned from `setInterval` and
+`setTimeout`. If their callback function throws, it will be caught by
+the domain 'error' handler.
+
+If the Timer or EventEmitter was already bound to a domain, it is removed
+from that one, and bound to this one instead.
+
+### domain.remove(emitter)
+
+* `emitter` {EventEmitter | Timer} emitter or timer to be removed from the domain
+
+The opposite of `domain.add(emitter)`. Removes domain handling from the
+specified emitter.
+
+### domain.bind(cb)
+
+* `cb` {Function} The callback function
+* return: {Function} The bound function
+
+The returned function will be a wrapper around the supplied callback
+function. When the returned function is called, any errors that are
+thrown will be routed to the domain's `error` event.
+
+#### Example
+
+ var d = domain.create();
+
+ function readSomeFile(filename, cb) {
+ fs.readFile(filename, d.bind(function(er, data) {
+ // if this throws, it will also be passed to the domain
+ return cb(er, JSON.parse(data));
+ }));
+ }
+
+ d.on('error', function(er) {
+ // an error occurred somewhere.
+ // if we throw it now, it will crash the program
+ // with the normal line number and stack message.
+ });
+
+### domain.intercept(cb)
+
+* `cb` {Function} The callback function
+* return: {Function} The intercepted function
+
+This method is almost identical to `domain.bind(cb)`. However, in
+addition to catching thrown errors, it will also intercept `Error`
+objects sent as the first argument to the function.
+
+In this way, the common `if (er) return cb(er);` pattern can be replaced
+with a single error handler in a single place.
+
+#### Example
+
+ var d = domain.create();
+
+ function readSomeFile(filename, cb) {
+ fs.readFile(filename, d.intercept(function(er, data) {
+ // if this throws, it will also be passed to the domain
+ // additionally, we know that 'er' will always be null,
+ // so the error-handling logic can be moved to the 'error'
+ // event on the domain instead of being repeated throughout
+ // the program.
+ return cb(er, JSON.parse(data));
+ }));
+ }
+
+ d.on('error', function(er) {
+ // an error occurred somewhere.
+ // if we throw it now, it will crash the program
+ // with the normal line number and stack message.
+ });
+
+### domain.dispose()
+
+The dispose method destroys a domain, and makes a best effort attempt to
+clean up any and all IO that is associated with the domain. Streams are
+aborted, ended, closed, and/or destroyed. Timers are cleared.
+Explicitly bound callbacks are no longer called. Any error events that
+are raised as a result of this are ignored.
+
+The intention of calling `dispose` is generally to prevent cascading
+errors when a critical part of the Domain context is found to be in an
+error state.
+
+Note that IO might still be performed. However, to the highest degree
+possible, once a domain is disposed, further errors from the emitters in
+that set will be ignored. So, even if some remaining actions are still
+in flight, Node.js will not communicate further about them.
Oops, something went wrong.

0 comments on commit 8673a4a

Please sign in to comment.