domain: share object and state with native land
authorTrevor Norris <trev.norris@gmail.com>
Wed, 7 Aug 2013 00:01:44 +0000 (17:01 -0700)
committerTrevor Norris <trev.norris@gmail.com>
Fri, 9 Aug 2013 23:54:45 +0000 (16:54 -0700)
Change process.domain to use a getter/setter and access that property
via an array index. These are much faster to get from c++, and it can be
passed to _setupDomainUse and stored as a Persistent<Array>.

InDomain() and GetDomain() as trivial ways to access the domain
information in the native layer. Important because we'll be able to
quickly access if a domain is active. Instead of just whether the domain
module has been loaded.

lib/domain.js
src/node.cc
src/node_internals.h
src/req_wrap.h

index ac02f45..588fb75 100644 (file)
@@ -32,8 +32,25 @@ var endMethods = ['end', 'abort', 'destroy', 'destroySoon'];
 // a few side effects.
 events.usingDomains = true;
 
+// overwrite process.domain with a getter/setter that will allow for more
+// effective optimizations
+var _domain = [null];
+Object.defineProperty(process, 'domain', {
+  enumerable: true,
+  get: function() {
+    return _domain[0];
+  },
+  set: function(arg) {
+    return _domain[0] = arg;
+  }
+});
+
+// objects with external array data are excellent ways to communicate state
+// between js and c++ w/o much overhead
+var _domain_flag = {};
+
 // let the process know we're using domains
-process._setupDomainUse();
+process._setupDomainUse(_domain, _domain_flag);
 
 exports.Domain = Domain;
 
@@ -64,6 +81,7 @@ Domain.prototype.enter = function() {
   // to push it onto the stack so that we can pop it later.
   exports.active = process.domain = this;
   stack.push(this);
+  _domain_flag[0] = stack.length;
 };
 
 Domain.prototype.exit = function() {
@@ -74,6 +92,7 @@ Domain.prototype.exit = function() {
   do {
     d = stack.pop();
   } while (d && d !== this);
+  _domain_flag[0] = stack.length;
 
   exports.active = stack[stack.length - 1];
   process.domain = exports.active;
index bb3ab87..7b1d843 100644 (file)
@@ -132,6 +132,7 @@ Persistent<Object> process_p;
 static Persistent<Function> process_tickCallback;
 static Persistent<Object> binding_cache;
 static Persistent<Array> module_load_list;
+static Persistent<Array> p_domain_box;
 
 static Cached<String> exports_symbol;
 
@@ -183,6 +184,11 @@ static struct {
   uint32_t last_threw;
 } tick_infobox;
 
+// easily communicate domain depth
+static struct {
+  uint32_t count;
+} domain_flag;
+
 #ifdef OPENSSL_NPN_NEGOTIATED
 static bool use_npn = true;
 #else
@@ -917,6 +923,33 @@ void SetupDomainUse(const FunctionCallbackInfo<Value>& args) {
   Local<Function> tdc = tdc_v.As<Function>();
   process->Set(FIXED_ONE_BYTE_STRING(node_isolate, "_tickCallback"), tdc);
   process_tickCallback.Reset(node_isolate, tdc);
+  if (!args[0]->IsArray()) {
+    fprintf(stderr, "_setupDomainUse first argument must be an array\n");
+    abort();
+  }
+  p_domain_box.Reset(node_isolate, args[0].As<Array>());
+  if (!args[1]->IsObject()) {
+    fprintf(stderr, "_setupDomainUse second argument must be an object\n");
+    abort();
+  }
+  Local<Object> flag = args[1].As<Object>();
+  flag->SetIndexedPropertiesToExternalArrayData(&domain_flag,
+                                                kExternalUnsignedIntArray,
+                                                1);
+}
+
+
+bool InDomain() {
+  return using_domains && domain_flag.count > 0;
+}
+
+
+Handle<Value> GetDomain() {
+  // no domain can exist if no domain module has been loaded
+  if (!InDomain() || p_domain_box.IsEmpty())
+    return Null(node_isolate);
+
+  return PersistentToLocal(node_isolate, p_domain_box)->Get(0);
 }
 
 
index 082368e..0c2bb0a 100644 (file)
@@ -218,9 +218,6 @@ NO_RETURN void FatalError(const char* location, const char* message);
     abort();                                                                \
   }
 
-// allow for quick domain check
-extern bool using_domains;
-
 enum Endianness {
   kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
   kBigEndian
@@ -378,6 +375,10 @@ inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
                                     length);
 }
 
+bool InDomain();
+
+v8::Handle<v8::Value> GetDomain();
+
 }  // namespace node
 
 #endif  // SRC_NODE_INTERNALS_H_
index eb73f06..1187df9 100644 (file)
@@ -23,6 +23,7 @@
 #define SRC_REQ_WRAP_H_
 
 #include "node.h"
+#include "node_internals.h"
 #include "queue.h"
 
 namespace node {
@@ -40,16 +41,10 @@ class ReqWrap {
     if (object.IsEmpty()) object = v8::Object::New();
     persistent().Reset(node_isolate, object);
 
-    if (using_domains) {
-      v8::Local<v8::Value> domain = v8::Context::GetCurrent()
-                                    ->Global()
-                                    ->Get(process_symbol)
-                                    ->ToObject()
-                                    ->Get(domain_symbol);
-
-      if (domain->IsObject()) {
+    if (InDomain()) {
+      v8::Local<v8::Value> domain = GetDomain();
+      if (domain->IsObject())
         object->Set(domain_symbol, domain);
-      }
     }
 
     QUEUE_INSERT_TAIL(&req_wrap_queue, &req_wrap_queue_);