couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [34/52] [partial] couchdb-nmo git commit: prepare for release
Date Wed, 14 Oct 2015 10:09:31 GMT
http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/cursor.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/cursor.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/cursor.js
new file mode 100644
index 0000000..ab82818
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/cursor.js
@@ -0,0 +1,756 @@
+"use strict";
+
+var Long = require('bson').Long
+  , Logger = require('./connection/logger')
+  , MongoError = require('./error')
+  , f = require('util').format;
+
+/**
+ * This is a cursor results callback
+ *
+ * @callback resultCallback
+ * @param {error} error An error object. Set to null if no error present
+ * @param {object} document
+ */
+
+/**
+ * @fileOverview The **Cursor** class is an internal class that embodies a cursor on MongoDB
+ * allowing for iteration over the results returned from the underlying query.
+ *
+ * **CURSORS Cannot directly be instantiated**
+ * @example
+ * var Server = require('mongodb-core').Server
+ *   , ReadPreference = require('mongodb-core').ReadPreference
+ *   , assert = require('assert');
+ *
+ * var server = new Server({host: 'localhost', port: 27017});
+ * // Wait for the connection event
+ * server.on('connect', function(server) {
+ *   assert.equal(null, err);
+ *
+ *   // Execute the write
+ *   var cursor = _server.cursor('integration_tests.inserts_example4', {
+ *       find: 'integration_tests.example4'
+ *     , query: {a:1}
+ *   }, {
+ *     readPreference: new ReadPreference('secondary');
+ *   });
+ *
+ *   // Get the first document
+ *   cursor.next(function(err, doc) {
+ *     assert.equal(null, err);
+ *     server.destroy();
+ *   });
+ * });
+ *
+ * // Start connecting
+ * server.connect();
+ */
+
+/**
+ * Creates a new Cursor, not to be used directly
+ * @class
+ * @param {object} bson An instance of the BSON parser
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {{object}|Long} cmd The selector (can be a command or a cursorId)
+ * @param {object} [options=null] Optional settings.
+ * @param {object} [options.batchSize=1000] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {object} [options.transforms=null] Transform methods for the cursor results
+ * @param {function} [options.transforms.query] Transform the value returned from the initial query
+ * @param {function} [options.transforms.doc] Transform each document returned from Cursor.prototype.next
+ * @param {object} topology The server topology instance.
+ * @param {object} topologyOptions The server topology options.
+ * @return {Cursor} A cursor instance
+ * @property {number} cursorBatchSize The current cursorBatchSize for the cursor
+ * @property {number} cursorLimit The current cursorLimit for the cursor
+ * @property {number} cursorSkip The current cursorSkip for the cursor
+ */
+var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
+  options = options || {};
+  // Cursor reference
+  var self = this;
+  // Initial query
+  var query = null;
+
+  // Cursor connection
+  this.connection = null;
+  // Cursor server
+  this.server = null;
+
+  // Do we have a not connected handler
+  this.disconnectHandler = options.disconnectHandler;
+
+  // Set local values
+  this.bson = bson;
+  this.ns = ns;
+  this.cmd = cmd;
+  this.options = options;
+  this.topology = topology;
+
+  // All internal state
+  this.cursorState = {
+      cursorId: null
+    , cmd: cmd
+    , documents: options.documents || []
+    , cursorIndex: 0
+    , dead: false
+    , killed: false
+    , init: false
+    , notified: false
+    , limit: options.limit || cmd.limit || 0
+    , skip: options.skip || cmd.skip || 0
+    , batchSize: options.batchSize || cmd.batchSize || 1000
+    , currentLimit: 0
+    // Result field name if not a cursor (contains the array of results)
+    , transforms: options.transforms
+  }
+
+  // Callback controller
+  this.callbacks = null;
+
+  // Logger
+  this.logger = Logger('Cursor', options);
+
+  //
+  // Did we pass in a cursor id
+  if(typeof cmd == 'number') {
+    this.cursorState.cursorId = Long.fromNumber(cmd);
+  } else if(cmd instanceof Long) {
+    this.cursorState.cursorId = cmd;
+  }
+}
+
+Cursor.prototype.setCursorBatchSize = function(value) {
+  this.cursorState.batchSize = value;
+}
+
+Cursor.prototype.cursorBatchSize = function() {
+  return this.cursorState.batchSize;
+}
+
+Cursor.prototype.setCursorLimit = function(value) {
+  this.cursorState.limit = value;
+}
+
+Cursor.prototype.cursorLimit = function() {
+  return this.cursorState.limit;
+}
+
+Cursor.prototype.setCursorSkip = function(value) {
+  this.cursorState.skip = value;
+}
+
+Cursor.prototype.cursorSkip = function() {
+  return this.cursorState.skip;
+}
+
+// //
+// // Execute getMore command
+// var execGetMore = function(self, callback) {
+// }
+
+//
+// Execute the first query
+var execInitialQuery = function(self, query, cmd, options, cursorState, connection, logger, callbacks, callback) {
+  if(logger.isDebug()) {
+    logger.debug(f("issue initial query [%s] with flags [%s]"
+      , JSON.stringify(cmd)
+      , JSON.stringify(query)));
+  }
+
+  var queryCallback = function(err, result) {
+    if(err) return callback(err);
+
+    if(result.queryFailure) {
+      return callback(MongoError.create(result.documents[0]), null);
+    }
+
+    // Check if we have a command cursor
+    if(Array.isArray(result.documents) && result.documents.length == 1
+      && (!cmd.find || (cmd.find && cmd.virtual == false))
+      && (result.documents[0].cursor != 'string'
+        || result.documents[0]['$err']
+        || result.documents[0]['errmsg']
+        || Array.isArray(result.documents[0].result))
+      ) {
+
+      // We have a an error document return the error
+      if(result.documents[0]['$err']
+        || result.documents[0]['errmsg']) {
+        return callback(MongoError.create(result.documents[0]), null);
+      }
+
+      // We have a cursor document
+      if(result.documents[0].cursor != null
+        && typeof result.documents[0].cursor != 'string') {
+          var id = result.documents[0].cursor.id;
+          // If we have a namespace change set the new namespace for getmores
+          if(result.documents[0].cursor.ns) {
+            self.ns = result.documents[0].cursor.ns;
+          }
+          // Promote id to long if needed
+          cursorState.cursorId = typeof id == 'number' ? Long.fromNumber(id) : id;
+          // If we have a firstBatch set it
+          if(Array.isArray(result.documents[0].cursor.firstBatch)) {
+            cursorState.documents = result.documents[0].cursor.firstBatch;//.reverse();
+          }
+
+          // Return after processing command cursor
+          return callback(null, null);
+      }
+
+      if(Array.isArray(result.documents[0].result)) {
+        cursorState.documents = result.documents[0].result;
+        cursorState.cursorId = Long.ZERO;
+        return callback(null, null);
+      }
+    }
+
+    // Otherwise fall back to regular find path
+    cursorState.cursorId = result.cursorId;
+    cursorState.documents = result.documents;
+
+    // Transform the results with passed in transformation method if provided
+    if(cursorState.transforms && typeof cursorState.transforms.query == 'function') {
+      cursorState.documents = cursorState.transforms.query(result);
+    }
+
+    // Return callback
+    callback(null, null);
+  }
+
+  // If we have a raw query decorate the function
+  if(options.raw || cmd.raw) {
+    queryCallback.raw = options.raw || cmd.raw;
+  }
+
+  // Do we have documentsReturnedIn set on the query
+  if(typeof query.documentsReturnedIn == 'string') {
+    queryCallback.documentsReturnedIn = query.documentsReturnedIn;
+  }
+
+  // Set up callback
+  callbacks.register(query.requestId, queryCallback);
+
+  // Write the initial command out
+  connection.write(query.toBin());
+}
+
+//
+// Handle callback (including any exceptions thrown)
+var handleCallback = function(callback, err, result) {
+  try {
+    callback(err, result);
+  } catch(err) {
+    process.nextTick(function() {
+      throw err;
+    });
+  }
+}
+
+
+// Internal methods
+Cursor.prototype._find = function(callback) {
+  var self = this;
+  // execInitialQuery(self, self.query, self.cmd, self.options, self.cursorState, self.connection, self.logger, self.callbacks, function(err, r) {
+  if(self.logger.isDebug()) {
+    self.logger.debug(f("issue initial query [%s] with flags [%s]"
+      , JSON.stringify(self.cmd)
+      , JSON.stringify(self.query)));
+  }
+
+  var queryCallback = function(err, result) {
+    if(err) return callback(err);
+
+    if(result.queryFailure) {
+      return callback(MongoError.create(result.documents[0]), null);
+    }
+
+    // Check if we have a command cursor
+    if(Array.isArray(result.documents) && result.documents.length == 1
+      && (!self.cmd.find || (self.cmd.find && self.cmd.virtual == false))
+      && (result.documents[0].cursor != 'string'
+        || result.documents[0]['$err']
+        || result.documents[0]['errmsg']
+        || Array.isArray(result.documents[0].result))
+      ) {
+
+      // We have a an error document return the error
+      if(result.documents[0]['$err']
+        || result.documents[0]['errmsg']) {
+        return callback(MongoError.create(result.documents[0]), null);
+      }
+
+      // We have a cursor document
+      if(result.documents[0].cursor != null
+        && typeof result.documents[0].cursor != 'string') {
+          var id = result.documents[0].cursor.id;
+          // If we have a namespace change set the new namespace for getmores
+          if(result.documents[0].cursor.ns) {
+            self.ns = result.documents[0].cursor.ns;
+          }
+          // Promote id to long if needed
+          self.cursorState.cursorId = typeof id == 'number' ? Long.fromNumber(id) : id;
+          // If we have a firstBatch set it
+          if(Array.isArray(result.documents[0].cursor.firstBatch)) {
+            self.cursorState.documents = result.documents[0].cursor.firstBatch;//.reverse();
+          }
+
+          // Return after processing command cursor
+          return callback(null, null);
+      }
+
+      if(Array.isArray(result.documents[0].result)) {
+        self.cursorState.documents = result.documents[0].result;
+        self.cursorState.cursorId = Long.ZERO;
+        return callback(null, null);
+      }
+    }
+
+    // Otherwise fall back to regular find path
+    self.cursorState.cursorId = result.cursorId;
+    self.cursorState.documents = result.documents;
+
+    // Transform the results with passed in transformation method if provided
+    if(self.cursorState.transforms && typeof self.cursorState.transforms.query == 'function') {
+      self.cursorState.documents = self.cursorState.transforms.query(result);
+    }
+
+    // Return callback
+    callback(null, null);
+  }
+  // console.log("------------------------- 2")
+
+  // If we have a raw query decorate the function
+  if(self.options.raw || self.cmd.raw) {
+    queryCallback.raw = self.options.raw || self.cmd.raw;
+  }
+  // console.log("------------------------- 3")
+
+  // Do we have documentsReturnedIn set on the query
+  if(typeof self.query.documentsReturnedIn == 'string') {
+    queryCallback.documentsReturnedIn = self.query.documentsReturnedIn;
+  }
+  // console.log("------------------------- 4")
+
+  // Set up callback
+  self.callbacks.register(self.query.requestId, queryCallback);
+
+  // Write the initial command out
+  self.connection.write(self.query.toBin());
+// console.log("------------------------- 5")
+}
+
+Cursor.prototype._getmore = function(callback) {
+  if(this.logger.isDebug()) this.logger.debug(f("schedule getMore call for query [%s]", JSON.stringify(this.query)))
+  // Determine if it's a raw query
+  var raw = this.options.raw || this.cmd.raw;
+  // We have a wire protocol handler
+  this.server.wireProtocolHandler.getMore(this.bson, this.ns, this.cursorState, this.cursorState.batchSize, raw, this.connection, this.callbacks, this.options, callback);
+}
+
+Cursor.prototype._killcursor = function(callback) {
+  // Set cursor to dead
+  this.cursorState.dead = true;
+  this.cursorState.killed = true;
+  // Remove documents
+  this.cursorState.documents = [];
+
+  // If no cursor id just return
+  if(this.cursorState.cursorId == null || this.cursorState.cursorId.isZero() || this.cursorState.init == false) {
+    if(callback) callback(null, null);
+    return;
+  }
+
+  // Execute command
+  this.server.wireProtocolHandler.killCursor(this.bson, this.ns, this.cursorState.cursorId, this.connection, this.callbacks, callback);
+}
+
+/**
+ * Clone the cursor
+ * @method
+ * @return {Cursor}
+ */
+Cursor.prototype.clone = function() {
+  return this.topology.cursor(this.ns, this.cmd, this.options);
+}
+
+/**
+ * Checks if the cursor is dead
+ * @method
+ * @return {boolean} A boolean signifying if the cursor is dead or not
+ */
+Cursor.prototype.isDead = function() {
+  return this.cursorState.dead == true;
+}
+
+/**
+ * Checks if the cursor was killed by the application
+ * @method
+ * @return {boolean} A boolean signifying if the cursor was killed by the application
+ */
+Cursor.prototype.isKilled = function() {
+  return this.cursorState.killed == true;
+}
+
+/**
+ * Checks if the cursor notified it's caller about it's death
+ * @method
+ * @return {boolean} A boolean signifying if the cursor notified the callback
+ */
+Cursor.prototype.isNotified = function() {
+  return this.cursorState.notified == true;
+}
+
+/**
+ * Returns current buffered documents length
+ * @method
+ * @return {number} The number of items in the buffered documents
+ */
+Cursor.prototype.bufferedCount = function() {
+  return this.cursorState.documents.length - this.cursorState.cursorIndex;
+}
+
+/**
+ * Returns current buffered documents
+ * @method
+ * @return {Array} An array of buffered documents
+ */
+Cursor.prototype.readBufferedDocuments = function(number) {
+  var unreadDocumentsLength = this.cursorState.documents.length - this.cursorState.cursorIndex;
+  var length = number < unreadDocumentsLength ? number : unreadDocumentsLength;
+  var elements = this.cursorState.documents.slice(this.cursorState.cursorIndex, this.cursorState.cursorIndex + length);
+
+  // Transform the doc with passed in transformation method if provided
+  if(this.cursorState.transforms && typeof this.cursorState.transforms.doc == 'function') {
+    // Transform all the elements
+    for(var i = 0; i < elements.length; i++) {
+      elements[i] = this.cursorState.transforms.doc(elements[i]);
+    }
+  }
+
+  // Ensure we do not return any more documents than the limit imposed
+  // Just return the number of elements up to the limit
+  if(this.cursorState.limit > 0 && (this.cursorState.currentLimit + elements.length) > this.cursorState.limit) {
+    elements = elements.slice(0, (this.cursorState.limit - this.cursorState.currentLimit));
+    this.kill();
+  }
+
+  // Adjust current limit
+  this.cursorState.currentLimit = this.cursorState.currentLimit + elements.length;
+  this.cursorState.cursorIndex = this.cursorState.cursorIndex + elements.length;
+
+  // Return elements
+  return elements;
+}
+
+/**
+ * Kill the cursor
+ * @method
+ * @param {resultCallback} callback A callback function
+ */
+Cursor.prototype.kill = function(callback) {
+  this._killcursor(callback);
+}
+
+/**
+ * Resets the cursor
+ * @method
+ * @return {null}
+ */
+Cursor.prototype.rewind = function() {
+  if(this.cursorState.init) {
+    if(!this.cursorState.dead) {
+      this.kill();
+    }
+
+    this.cursorState.currentLimit = 0;
+    this.cursorState.init = false;
+    this.cursorState.dead = false;
+    this.cursorState.killed = false;
+    this.cursorState.notified = false;
+    this.cursorState.documents = [];
+    this.cursorState.cursorId = null;
+    this.cursorState.cursorIndex = 0;
+  }
+}
+
+/**
+ * Validate if the connection is dead and return error
+ */
+var isConnectionDead = function(self, callback) {
+  if(self.connection
+    && !self.connection.isConnected()) {
+    self.cursorState.notified = true;
+    self.cursorState.killed = true;
+    self.cursorState.documents = [];
+    self.cursorState.cursorIndex = 0;
+    callback(MongoError.create(f('connection to host %s:%s was destroyed', self.connection.host, self.connection.port)))
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Validate if the cursor is dead but was not explicitly killed by user
+ */
+var isCursorDeadButNotkilled = function(self, callback) {
+  // Cursor is dead but not marked killed, return null
+  if(self.cursorState.dead && !self.cursorState.killed) {
+    self.cursorState.notified = true;
+    self.cursorState.killed = true;
+    self.cursorState.documents = [];
+    self.cursorState.cursorIndex = 0;
+    handleCallback(callback, null, null);
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Validate if the cursor is dead and was killed by user
+ */
+var isCursorDeadAndKilled = function(self, callback) {
+  if(self.cursorState.dead && self.cursorState.killed) {
+    handleCallback(callback, MongoError.create("cursor is dead"));
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Validate if the cursor was killed by the user
+ */
+var isCursorKilled = function(self, callback) {
+  if(self.cursorState.killed) {
+    self.cursorState.notified = true;
+    self.cursorState.documents = [];
+    self.cursorState.cursorIndex = 0;
+    handleCallback(callback, null, null);
+    return true;
+  }
+
+  return false;
+}
+
+/**
+ * Mark cursor as being dead and notified
+ */
+var setCursorDeadAndNotified = function(self, callback) {
+  self.cursorState.dead = true;
+  self.cursorState.notified = true;
+  self.cursorState.documents = [];
+  self.cursorState.cursorIndex = 0;
+  handleCallback(callback, null, null);
+}
+
+/**
+ * Mark cursor as being notified
+ */
+var setCursorNotified = function(self, callback) {
+  self.cursorState.notified = true;
+  self.cursorState.documents = [];
+  self.cursorState.cursorIndex = 0;
+  handleCallback(callback, null, null);
+}
+
+var nextFunction = function(self, callback) {
+  // We have notified about it
+  if(self.cursorState.notified) {
+    return callback(new Error('cursor is exhausted'));
+  }
+
+  // Cursor is killed return null
+  if(isCursorKilled(self, callback)) return;
+
+  // Cursor is dead but not marked killed, return null
+  if(isCursorDeadButNotkilled(self, callback)) return;
+
+  // We have a dead and killed cursor, attempting to call next should error
+  if(isCursorDeadAndKilled(self, callback)) return;
+
+  // We have just started the cursor
+  if(!self.cursorState.init) {
+    // Topology is not connected, save the call in the provided store to be
+    // Executed at some point when the handler deems it's reconnected
+    if(!self.topology.isConnected(self.options) && self.disconnectHandler != null) {
+      return self.disconnectHandler.addObjectAndMethod('cursor', self, 'next', [callback], callback);
+    }
+
+    try {
+      // Get a server
+      self.server = self.topology.getServer(self.options);
+      // Get a connection
+      self.connection = self.server.getConnection();
+      // Get the callbacks
+      self.callbacks = self.server.getCallbacks();
+    } catch(err) {
+      return callback(err);
+    }
+
+    // Set as init
+    self.cursorState.init = true;
+
+    try {
+      // Get the right wire protocol command
+      self.query = self.server.wireProtocolHandler.command(self.bson, self.ns, self.cmd, self.cursorState, self.topology, self.options);
+    } catch(err) {
+      return callback(err);
+    }
+  }
+
+  // Process exhaust messages
+  var processExhaustMessages = function(err, result) {
+    if(err) {
+      self.cursorState.dead = true;
+      self.callbacks.unregister(self.query.requestId);
+      return callback(err);
+    }
+
+    // Concatenate all the documents
+    self.cursorState.documents = self.cursorState.documents.concat(result.documents);
+
+    // If we have no documents left
+    if(Long.ZERO.equals(result.cursorId)) {
+      self.cursorState.cursorId = Long.ZERO;
+      self.callbacks.unregister(self.query.requestId);
+      return nextFunction(self, callback);
+    }
+
+    // Set up next listener
+    self.callbacks.register(result.requestId, processExhaustMessages)
+
+    // Initial result
+    if(self.cursorState.cursorId == null) {
+      self.cursorState.cursorId = result.cursorId;
+      nextFunction(self, callback);
+    }
+  }
+
+  // If we have exhaust
+  if(self.cmd.exhaust && self.cursorState.cursorId == null) {
+    // Handle all the exhaust responses
+    self.callbacks.register(self.query.requestId, processExhaustMessages);
+    // Write the initial command out
+    return self.connection.write(self.query.toBin());
+  } else if(self.cmd.exhaust && self.cursorState.cursorIndex < self.cursorState.documents.length) {
+    return handleCallback(callback, null, self.cursorState.documents[self.cursorState.cursorIndex++]);
+  } else if(self.cmd.exhaust && Long.ZERO.equals(self.cursorState.cursorId)) {
+    self.callbacks.unregister(self.query.requestId);
+    return setCursorNotified(self, callback);
+  } else if(self.cmd.exhaust) {
+    return setTimeout(function() {
+      if(Long.ZERO.equals(self.cursorState.cursorId)) return;
+      nextFunction(self, callback);
+    }, 1);
+  }
+
+  // If we don't have a cursorId execute the first query
+  if(self.cursorState.cursorId == null) {
+    // Check if connection is dead and return if not possible to
+    // execute the query against the db
+    if(isConnectionDead(self, callback)) return;
+
+    // Check if topology is destroyed
+    if(self.topology.isDestroyed()) return callback(new MongoError(f('connection destroyed, not possible to instantiate cursor')));
+
+    // query, cmd, options, cursorState, callback
+    self._find(function(err, r) {
+      if(err) return handleCallback(callback, err, null);
+      if(self.cursorState.documents.length == 0 && !self.cmd.tailable && !self.cmd.awaitData) {
+        return setCursorNotified(self, callback);
+      }
+
+      nextFunction(self, callback);
+    });
+  } else if(self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
+    // Ensure we kill the cursor on the server
+    self.kill();
+    // Set cursor in dead and notified state
+    return setCursorDeadAndNotified(self, callback);
+  } else if(self.cursorState.cursorIndex == self.cursorState.documents.length
+      && !Long.ZERO.equals(self.cursorState.cursorId)) {
+      // Ensure an empty cursor state
+      self.cursorState.documents = [];
+      self.cursorState.cursorIndex = 0;
+
+      // Check if topology is destroyed
+      if(self.topology.isDestroyed()) return callback(new MongoError(f('connection destroyed, not possible to instantiate cursor')));
+
+      // Check if connection is dead and return if not possible to
+      // execute a getmore on this connection
+      if(isConnectionDead(self, callback)) return;
+
+      // Execute the next get more
+      self._getmore(function(err, doc) {
+        if(err) return handleCallback(callback, err);
+        if(self.cursorState.documents.length == 0
+          && Long.ZERO.equals(self.cursorState.cursorId)) {
+            self.cursorState.dead = true;
+          }
+
+        // Tailable cursor getMore result, notify owner about it
+        // No attempt is made here to retry, this is left to the user of the
+        // core module to handle to keep core simple
+        if(self.cursorState.documents.length == 0 && self.cmd.tailable) {
+          return handleCallback(callback, MongoError.create({
+              message: "No more documents in tailed cursor"
+            , tailable: self.cmd.tailable
+            , awaitData: self.cmd.awaitData
+          }));
+        }
+
+        if(self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
+          return setCursorDeadAndNotified(self, callback);
+        }
+
+        nextFunction(self, callback);
+      });
+  } else if(self.cursorState.documents.length == self.cursorState.cursorIndex
+    && self.cmd.tailable) {
+      return handleCallback(callback, MongoError.create({
+          message: "No more documents in tailed cursor"
+        , tailable: self.cmd.tailable
+        , awaitData: self.cmd.awaitData
+      }));
+  } else if(self.cursorState.documents.length == self.cursorState.cursorIndex
+      && Long.ZERO.equals(self.cursorState.cursorId)) {
+      setCursorDeadAndNotified(self, callback);
+  } else {
+    if(self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
+      // Ensure we kill the cursor on the server
+      self.kill();
+      // Set cursor in dead and notified state
+      return setCursorDeadAndNotified(self, callback);
+    }
+
+    // Increment the current cursor limit
+    self.cursorState.currentLimit += 1;
+
+    // Get the document
+    var doc = self.cursorState.documents[self.cursorState.cursorIndex++];
+
+    // Transform the doc with passed in transformation method if provided
+    if(self.cursorState.transforms && typeof self.cursorState.transforms.doc == 'function') {
+      doc = self.cursorState.transforms.doc(doc);
+    }
+
+    // Return the document
+    handleCallback(callback, null, doc);
+  }
+}
+
+/**
+ * Retrieve the next document from the cursor
+ * @method
+ * @param {resultCallback} callback A callback function
+ */
+Cursor.prototype.next = function(callback) {
+  nextFunction(this, callback);
+}
+
+module.exports = Cursor;

http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/error.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/error.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/error.js
new file mode 100644
index 0000000..4e17ef3
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/error.js
@@ -0,0 +1,44 @@
+"use strict";
+
+/**
+ * Creates a new MongoError
+ * @class
+ * @augments Error
+ * @param {string} message The error message
+ * @return {MongoError} A MongoError instance
+ */
+function MongoError(message) {
+  this.name = 'MongoError';
+  this.message = message;
+  Error.captureStackTrace(this, MongoError);
+}
+
+/**
+ * Creates a new MongoError object
+ * @method
+ * @param {object} options The error options
+ * @return {MongoError} A MongoError instance
+ */
+MongoError.create = function(options) {
+  var err = null;
+
+  if(options instanceof Error) {
+    err = new MongoError(options.message);
+    err.stack = options.stack;
+  } else if(typeof options == 'string') {
+    err = new MongoError(options);
+  } else {
+    err = new MongoError(options.message || options.errmsg || options.$err || "n/a");
+    // Other options
+    for(var name in options) {
+      err[name] = options[name];
+    }
+  }
+
+  return err;
+}
+
+// Extend JavaScript error
+MongoError.prototype = new Error; 
+
+module.exports = MongoError;

http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/tools/smoke_plugin.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/tools/smoke_plugin.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/tools/smoke_plugin.js
new file mode 100644
index 0000000..dcceda4
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/tools/smoke_plugin.js
@@ -0,0 +1,59 @@
+var fs = require('fs');
+
+/* Note: because this plugin uses process.on('uncaughtException'), only one
+ * of these can exist at any given time. This plugin and anything else that
+ * uses process.on('uncaughtException') will conflict. */
+exports.attachToRunner = function(runner, outputFile) {
+  var smokeOutput = { results : [] };
+  var runningTests = {};
+
+  var integraPlugin = {
+    beforeTest: function(test, callback) {
+      test.startTime = Date.now();
+      runningTests[test.name] = test;
+      callback();
+    },
+    afterTest: function(test, callback) {
+      smokeOutput.results.push({
+        status: test.status,
+        start: test.startTime,
+        end: Date.now(),
+        test_file: test.name,
+        exit_code: 0,
+        url: ""
+      });
+      delete runningTests[test.name];
+      callback();
+    },
+    beforeExit: function(obj, callback) {
+      fs.writeFile(outputFile, JSON.stringify(smokeOutput), function() {
+        callback();
+      });
+    }
+  };
+
+  // In case of exception, make sure we write file
+  process.on('uncaughtException', function(err) {
+    // Mark all currently running tests as failed
+    for (var testName in runningTests) {
+      smokeOutput.results.push({
+        status: "fail",
+        start: runningTests[testName].startTime,
+        end: Date.now(),
+        test_file: testName,
+        exit_code: 0,
+        url: ""
+      });
+    }
+
+    // write file
+    fs.writeFileSync(outputFile, JSON.stringify(smokeOutput));
+
+    // Standard NodeJS uncaught exception handler
+    console.error(err.stack);
+    process.exit(1);
+  });
+
+  runner.plugin(integraPlugin);
+  return integraPlugin;
+};

http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/command_result.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/command_result.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/command_result.js
new file mode 100644
index 0000000..ff7bf1b
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/command_result.js
@@ -0,0 +1,37 @@
+"use strict";
+
+var setProperty = require('../connection/utils').setProperty
+  , getProperty = require('../connection/utils').getProperty
+  , getSingleProperty = require('../connection/utils').getSingleProperty;
+
+/**
+ * Creates a new CommandResult instance
+ * @class
+ * @param {object} result CommandResult object
+ * @param {Connection} connection A connection instance associated with this result
+ * @return {CommandResult} A cursor instance
+ */
+var CommandResult = function(result, connection) {
+  this.result = result;
+  this.connection = connection;
+}
+
+/**
+ * Convert CommandResult to JSON
+ * @method
+ * @return {object}
+ */
+CommandResult.prototype.toJSON = function() {
+  return this.result;
+}
+
+/**
+ * Convert CommandResult to String representation
+ * @method
+ * @return {string}
+ */
+CommandResult.prototype.toString = function() {
+  return JSON.stringify(this.toJSON());
+}
+
+module.exports = CommandResult;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/mongos.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/mongos.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/mongos.js
new file mode 100644
index 0000000..c54514a
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/mongos.js
@@ -0,0 +1,1000 @@
+"use strict";
+
+var inherits = require('util').inherits
+  , f = require('util').format
+  , b = require('bson')
+  , bindToCurrentDomain = require('../connection/utils').bindToCurrentDomain
+  , EventEmitter = require('events').EventEmitter
+  , BasicCursor = require('../cursor')
+  , BSON = require('bson').native().BSON
+  , BasicCursor = require('../cursor')
+  , Server = require('./server')
+  , Logger = require('../connection/logger')
+  , ReadPreference = require('./read_preference')
+  , Session = require('./session')
+  , MongoError = require('../error');
+
+/**
+ * @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
+ * used to construct connections.
+ * 
+ * @example
+ * var Mongos = require('mongodb-core').Mongos
+ *   , ReadPreference = require('mongodb-core').ReadPreference
+ *   , assert = require('assert');
+ * 
+ * var server = new Mongos([{host: 'localhost', port: 30000}]);
+ * // Wait for the connection event
+ * server.on('connect', function(server) {
+ *   server.destroy();
+ * });
+ * 
+ * // Start connecting
+ * server.connect();
+ */
+
+var DISCONNECTED = 'disconnected';
+var CONNECTING = 'connecting';
+var CONNECTED = 'connected';
+var DESTROYED = 'destroyed';
+
+// All bson types
+var bsonTypes = [b.Long, b.ObjectID, b.Binary, b.Code, b.DBRef, b.Symbol, b.Double, b.Timestamp, b.MaxKey, b.MinKey];
+// BSON parser
+var bsonInstance = null;
+
+// Instance id
+var mongosId = 0;
+
+//
+// Clone the options
+var cloneOptions = function(options) {
+  var opts = {};
+  for(var name in options) {
+    opts[name] = options[name];
+  }
+  return opts;
+}
+
+var State = function(readPreferenceStrategies) {
+  // Internal state
+  this.s = {
+      connectedServers: []
+    , disconnectedServers: []
+    , readPreferenceStrategies: readPreferenceStrategies
+  }
+}
+
+//
+// A Mongos connected
+State.prototype.connected = function(server) {
+  // Locate in disconnected servers and remove
+  this.s.disconnectedServers = this.s.disconnectedServers.filter(function(s) {
+    return !s.equals(server);
+  });
+
+  var found = false;
+  // Check if the server exists
+  this.s.connectedServers.forEach(function(s) {
+    if(s.equals(server)) found = true;
+  });
+
+  // Add to disconnected list if it does not already exist
+  if(!found) this.s.connectedServers.push(server);
+}
+
+//
+// A Mongos disconnected
+State.prototype.disconnected = function(server) {
+  // Locate in disconnected servers and remove
+  this.s.connectedServers = this.s.connectedServers.filter(function(s) {
+    return !s.equals(server);
+  });
+
+  var found = false;
+  // Check if the server exists
+  this.s.disconnectedServers.forEach(function(s) {
+    if(s.equals(server)) found = true;
+  });
+
+  // Add to disconnected list if it does not already exist
+  if(!found) this.s.disconnectedServers.push(server);
+}
+
+//
+// Return the list of disconnected servers
+State.prototype.disconnectedServers = function() {
+  return this.s.disconnectedServers.slice(0);
+}
+
+//
+// Get connectedServers
+State.prototype.connectedServers = function() {
+  return this.s.connectedServers.slice(0)
+}
+
+//
+// Get all servers
+State.prototype.getAll = function() {
+  return this.s.connectedServers.slice(0).concat(this.s.disconnectedServers);
+}
+
+//
+// Get all connections
+State.prototype.getAllConnections = function() {
+  var connections = [];
+  this.s.connectedServers.forEach(function(e) {
+    connections = connections.concat(e.connections());
+  });
+  return connections;
+}
+
+//
+// Destroy the state
+State.prototype.destroy = function() {
+  // Destroy any connected servers
+  while(this.s.connectedServers.length > 0) {
+    var server = this.s.connectedServers.shift();
+
+    // Remove any non used handlers
+    ['error', 'close', 'timeout', 'connect'].forEach(function(e) {
+      server.removeAllListeners(e);
+    })
+
+    // Server destroy
+    server.destroy();
+    // Add to list of disconnected servers
+    this.s.disconnectedServers.push(server);
+  }        
+}
+
+//
+// Are we connected
+State.prototype.isConnected = function() {
+  return this.s.connectedServers.length > 0;
+}
+
+//
+// Pick a server
+State.prototype.pickServer = function(readPreference) {
+  readPreference = readPreference || ReadPreference.primary;
+
+  // Do we have a custom readPreference strategy, use it
+  if(this.s.readPreferenceStrategies != null && this.s.readPreferenceStrategies[readPreference] != null) {
+    return this.s.readPreferenceStrategies[readPreference].pickServer(connectedServers, readPreference);
+  }
+
+  // No valid connections
+  if(this.s.connectedServers.length == 0) throw new MongoError("no mongos proxy available");
+  // Pick first one
+  return this.s.connectedServers[0];
+}
+
+/**
+ * Creates a new Mongos instance
+ * @class
+ * @param {array} seedlist A list of seeds for the replicaset
+ * @param {number} [options.reconnectTries=30] Reconnect retries for HA if no servers available
+ * @param {number} [options.haInterval=5000] The High availability period for replicaset inquiry
+ * @param {boolean} [options.emitError=false] Server will emit errors events
+ * @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
+ * @param {number} [options.size=5] Server connection pool size
+ * @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
+ * @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
+ * @param {boolean} [options.noDelay=true] TCP Connection no delay
+ * @param {number} [options.connectionTimeout=1000] TCP Connection timeout setting
+ * @param {number} [options.socketTimeout=0] TCP Socket timeout setting
+ * @param {boolean} [options.singleBufferSerializtion=true] Serialize into single buffer, trade of peak memory for serialization speed
+ * @param {boolean} [options.ssl=false] Use SSL for connection
+ * @param {Buffer} [options.ca] SSL Certificate store binary buffer
+ * @param {Buffer} [options.cert] SSL Certificate binary buffer
+ * @param {Buffer} [options.key] SSL Key file binary buffer
+ * @param {string} [options.passphrase] SSL Certificate pass phrase
+ * @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
+ * @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
+ * @return {Mongos} A cursor instance
+ * @fires Mongos#connect
+ * @fires Mongos#joined
+ * @fires Mongos#left
+ */
+var Mongos = function(seedlist, options) {  
+  var self = this;
+  options = options || {};
+  
+  // Add event listener
+  EventEmitter.call(this);
+
+  // Validate seedlist
+  if(!Array.isArray(seedlist)) throw new MongoError("seedlist must be an array");
+  // Validate list
+  if(seedlist.length == 0) throw new MongoError("seedlist must contain at least one entry");
+  // Validate entries
+  seedlist.forEach(function(e) {
+    if(typeof e.host != 'string' || typeof e.port != 'number') 
+      throw new MongoError("seedlist entry must contain a host and port");
+  });
+
+  // BSON Parser, ensure we have a single instance
+  bsonInstance = bsonInstance == null ? new BSON(bsonTypes) : bsonInstance;
+  // Pick the right bson parser
+  var bson = options.bson ? options.bson : bsonInstance;
+  // Add bson parser to options
+  options.bson = bson;
+
+  // The Mongos state
+  this.s = {
+    // Seed list for sharding passed in
+      seedlist: seedlist
+    // Passed in options
+    , options: options
+    // Logger
+    , logger: Logger('Mongos', options)
+    // Reconnect tries
+    , reconnectTries: options.reconnectTries || 30
+    // Ha interval
+    , haInterval: options.haInterval || 5000
+    // Have omitted fullsetup
+    , fullsetup: false
+    // Cursor factory
+    , Cursor: options.cursorFactory || BasicCursor
+    // Current credentials used for auth
+    , credentials: []
+    // BSON Parser
+    , bsonInstance: bsonInstance
+    , bson: bson
+    // Default state
+    , state: DISCONNECTED
+    // Swallow or emit errors
+    , emitError: typeof options.emitError == 'boolean' ? options.emitError : false
+    // Contains any alternate strategies for picking
+    , readPreferenceStrategies: {}
+    // Auth providers
+    , authProviders: {}
+    // Unique instance id
+    , id: mongosId++
+    // Authentication in progress
+    , authInProgress: false
+    // Servers added while auth in progress
+    , authInProgressServers: []
+    // Current retries left
+    , retriesLeft: options.reconnectTries || 30
+    // Do we have a not connected handler
+    , disconnectHandler: options.disconnectHandler
+  }
+
+  // Set up the connection timeout for the options
+  options.connectionTimeout = options.connectionTimeout || 1000;
+
+  // Create a new state for the mongos
+  this.s.mongosState = new State(this.s.readPreferenceStrategies);
+
+  // BSON property (find a server and pass it along)
+  Object.defineProperty(this, 'bson', {
+    enumerable: true, get: function() { 
+      var servers = self.s.mongosState.getAll();
+      return servers.length > 0 ? servers[0].bson : null; 
+    }
+  });
+
+  Object.defineProperty(this, 'id', {
+    enumerable:true, get: function() { return self.s.id; }
+  });
+
+  Object.defineProperty(this, 'type', {
+    enumerable:true, get: function() { return 'mongos'; }
+  });
+
+  Object.defineProperty(this, 'haInterval', {
+    enumerable:true, get: function() { return self.s.haInterval; }
+  });
+
+  Object.defineProperty(this, 'state', {
+    enumerable:true, get: function() { return self.s.mongosState; }
+  });
+}
+
+inherits(Mongos, EventEmitter);
+
+/**
+ * Name of BSON parser currently used
+ * @method
+ * @return {string}
+ */
+Mongos.prototype.parserType = function() {
+  if(this.s.bson.serialize.toString().indexOf('[native code]') != -1)
+    return 'c++';
+  return 'js';
+}
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} type Type of BSON parser to use (c++ or js)
+ */
+Mongos.prototype.setBSONParserType = function(type) {
+  var nBSON = null;
+
+  if(type == 'c++') {
+    nBSON = require('bson').native().BSON;
+  } else if(type == 'js') {
+    nBSON = require('bson').pure().BSON;
+  } else {
+    throw new MongoError(f("% parser not supported", type));
+  }
+
+  this.s.options.bson = new nBSON(bsonTypes);
+}  
+
+/**
+ * Returns the last known ismaster document for this server
+ * @method
+ * @return {object}
+ */
+Mongos.prototype.lastIsMaster = function() {
+  var connectedServers = this.s.mongosState.connectedServers();
+  if(connectedServers.length > 0) return connectedServers[0].lastIsMaster();
+  return null; 
+}
+
+/**
+ * Initiate server connect
+ * @method
+ */
+Mongos.prototype.connect = function(_options) {
+  var self = this;
+  // Start replicaset inquiry process
+  setTimeout(mongosInquirer(self, self.s), self.s.haInterval);
+  // Additional options
+  if(_options) for(var name in _options) self.s.options[name] = _options[name];
+  // For all entries in the seedlist build a server instance
+  self.s.seedlist.forEach(function(e) {
+    // Clone options
+    var opts = cloneOptions(self.s.options);
+    // Add host and port
+    opts.host = e.host;
+    opts.port = e.port;
+    opts.reconnect = false;
+    opts.readPreferenceStrategies = self.s.readPreferenceStrategies;
+    // Share the auth store
+    opts.authProviders = self.s.authProviders;
+    // Don't emit errors
+    opts.emitError = true;
+    // Create a new Server
+    self.s.mongosState.disconnected(new Server(opts));
+  });
+
+  // Get the disconnected servers
+  var servers = self.s.mongosState.disconnectedServers();
+
+  // Attempt to connect to all the servers
+  while(servers.length > 0) {
+    // Get the server
+    var server = servers.shift();      
+
+    // Remove any non used handlers
+    ['error', 'close', 'timeout', 'connect', 'message', 'parseError'].forEach(function(e) {
+      server.removeAllListeners(e);
+    });
+
+    // Set up the event handlers
+    server.once('error', errorHandlerTemp(self, self.s, server));
+    server.once('close', errorHandlerTemp(self, self.s, server));
+    server.once('timeout', errorHandlerTemp(self, self.s, server));
+    server.once('parseError', errorHandlerTemp(self, self.s, server));
+    server.once('connect', connectHandler(self, self.s, 'connect'));
+
+    if(self.s.logger.isInfo()) self.s.logger.info(f('connecting to server %s', server.name));
+    // Attempt to connect
+    server.connect();
+  }
+}
+
+/**
+ * Destroy the server connection
+ * @method
+ */
+Mongos.prototype.destroy = function(emitClose) {
+  this.s.state = DESTROYED;
+  // Emit close
+  if(emitClose && self.listeners('close').length > 0) self.emit('close', self);
+  // Destroy the state
+  this.s.mongosState.destroy();
+}
+
+/**
+ * Figure out if the server is connected
+ * @method
+ * @return {boolean}
+ */
+Mongos.prototype.isConnected = function() {
+  return this.s.mongosState.isConnected();
+}
+
+/**
+ * Figure out if the server instance was destroyed by calling destroy
+ * @method
+ * @return {boolean}
+ */
+Mongos.prototype.isDestroyed = function() {
+  return this.s.state  == DESTROYED;
+}
+
+//
+// Operations
+//
+
+/**
+ * Insert one or more documents
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of documents to insert
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized. 
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.insert = function(ns, ops, options, callback) {
+  if(typeof options == 'function') callback = options, options = {};
+  if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
+  // Topology is not connected, save the call in the provided store to be
+  // Executed at some point when the handler deems it's reconnected
+  if(!this.isConnected() && this.s.disconnectHandler != null) {
+    callback = bindToCurrentDomain(callback);
+    return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
+  }
+
+  executeWriteOperation(this.s, 'insert', ns, ops, options, callback);
+}
+
+/**
+ * Perform one or more update operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of updates
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized. 
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.update = function(ns, ops, options, callback) {
+  if(typeof options == 'function') callback = options, options = {};
+  if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
+  // Topology is not connected, save the call in the provided store to be
+  // Executed at some point when the handler deems it's reconnected
+  if(!this.isConnected() && this.s.disconnectHandler != null) {
+    callback = bindToCurrentDomain(callback);
+    return this.s.disconnectHandler.add('update', ns, ops, options, callback);
+  }
+
+  executeWriteOperation(this.s, 'update', ns, ops, options, callback);
+}
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {array} ops An array of removes
+ * @param {boolean} [options.ordered=true] Execute in order or out of order
+ * @param {object} [options.writeConcern={}] Write concern for the operation
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized. 
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.remove = function(ns, ops, options, callback) {
+  if(typeof options == 'function') callback = options, options = {};
+  if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
+  // Topology is not connected, save the call in the provided store to be
+  // Executed at some point when the handler deems it's reconnected
+  if(!this.isConnected() && this.s.disconnectHandler != null) {
+    callback = bindToCurrentDomain(callback);
+    return this.s.disconnectHandler.add('remove', ns, ops, options, callback);
+  }
+
+  executeWriteOperation(this.s, 'remove', ns, ops, options, callback);
+}    
+
+/**
+ * Execute a command
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {object} cmd The command hash
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Connection} [options.connection] Specify connection object to execute command against
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized. 
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.command = function(ns, cmd, options, callback) {
+  if(typeof options == 'function') callback = options, options = {};
+  if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
+  var self = this;
+
+  // Topology is not connected, save the call in the provided store to be
+  // Executed at some point when the handler deems it's reconnected
+  if(!self.isConnected() && self.s.disconnectHandler != null) {
+    callback = bindToCurrentDomain(callback);
+    return self.s.disconnectHandler.add('command', ns, cmd, options, callback);
+  }
+
+  var server = null;
+  // Ensure we have no options
+  options = options || {};
+
+  // We need to execute the command on all servers
+  if(options.onAll) {
+    var servers = self.s.mongosState.getAll();
+    var count = servers.length;
+    var cmdErr = null;
+
+    for(var i = 0; i < servers.length; i++) {
+      servers[i].command(ns, cmd, options, function(err, r) {
+        count = count - 1;
+        // Finished executing command
+        if(count == 0) {
+          // Was it a logout command clear any credentials      
+          if(cmd.logout) clearCredentials(state, ns);
+          // Return the error
+          callback(err, r);
+        }
+      });
+    }
+
+    return;
+  }
+
+
+  try {
+    // Get a primary      
+    server = self.s.mongosState.pickServer(options.writeConcern ? ReadPreference.primary : options.readPreference);
+  } catch(err) {
+    return callback(err);
+  }
+
+  // No server returned we had an error
+  if(server == null) return callback(new MongoError("no mongos found"));
+  server.command(ns, cmd, options, function(err, r) {
+    // Was it a logout command clear any credentials      
+    if(cmd.logout) clearCredentials(self.s, ns);
+    callback(err, r);      
+  });
+}
+
+/**
+ * Perform one or more remove operations
+ * @method
+ * @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
+ * @param {{object}|{Long}} cmd Can be either a command returning a cursor or a cursorId
+ * @param {object} [options.batchSize=0] Batchsize for the operation
+ * @param {array} [options.documents=[]] Initial documents list for cursor
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized. 
+ * @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
+ * @param {opResultCallback} callback A callback function
+ */
+Mongos.prototype.cursor = function(ns, cmd, cursorOptions) {
+  cursorOptions = cursorOptions || {};
+  var FinalCursor = cursorOptions.cursorFactory || this.s.Cursor;
+  return new FinalCursor(this.s.bson, ns, cmd, cursorOptions, this, this.s.options);
+}
+
+/**
+ * Authenticate using a specified mechanism
+ * @method
+ * @param {string} mechanism The Auth mechanism we are invoking
+ * @param {string} db The db we are invoking the mechanism against
+ * @param {...object} param Parameters for the specific mechanism
+ * @param {authResultCallback} callback A callback function
+ */
+Mongos.prototype.auth = function(mechanism, db) {
+  var allArgs = Array.prototype.slice.call(arguments, 0).slice(0);
+  var self = this;
+  var args = Array.prototype.slice.call(arguments, 2);
+  var callback = args.pop();
+
+  // If we don't have the mechanism fail
+  if(this.s.authProviders[mechanism] == null && mechanism != 'default')
+    throw new MongoError(f("auth provider %s does not exist", mechanism));
+
+  // Authenticate against all the servers
+  var servers = this.s.mongosState.connectedServers().slice(0);
+  var count = servers.length;
+  // Correct authentication
+  var authenticated = true;
+  var authErr = null;
+  // Set auth in progress
+  this.s.authInProgress = true;
+
+  // Authenticate against all servers
+  while(servers.length > 0) {
+    var server = servers.shift();
+    // Arguments without a callback
+    var argsWithoutCallback = [mechanism, db].concat(args.slice(0));
+    // Create arguments
+    var finalArguments = argsWithoutCallback.concat([function(err, r) {
+      count = count - 1;
+      if(err) authErr = err;
+      if(!r) authenticated = false;
+
+      // We are done
+      if(count == 0) {
+        // We have more servers that are not authenticated, let's authenticate
+        if(self.s.authInProgressServers.length > 0) {
+          self.s.authInProgressServers = [];
+          return self.auth.apply(self, [mechanism, db].concat(args).concat([callback]));
+        }
+
+        // Auth is done
+        self.s.authInProgress = false;
+        // Add successful credentials
+        if(authErr == null) addCredentials(self.s, db, argsWithoutCallback);
+        // Return the auth error
+        if(authErr) return callback(authErr, false);
+        // Successfully authenticated session
+        callback(null, new Session({}, self));
+      }
+    }]);
+
+    // Execute the auth
+    server.auth.apply(server, finalArguments);
+  }
+}  
+
+//
+// Plugin methods
+//
+
+/**
+ * Add custom read preference strategy
+ * @method
+ * @param {string} name Name of the read preference strategy
+ * @param {object} strategy Strategy object instance
+ */
+Mongos.prototype.addReadPreferenceStrategy = function(name, strategy) {
+  if(this.s.readPreferenceStrategies == null) this.s.readPreferenceStrategies = {};
+  this.s.readPreferenceStrategies[name] = strategy;
+}
+
+/**
+ * Add custom authentication mechanism
+ * @method
+ * @param {string} name Name of the authentication mechanism
+ * @param {object} provider Authentication object instance
+ */
+Mongos.prototype.addAuthProvider = function(name, provider) {
+  this.s.authProviders[name] = provider;
+}
+
+/**
+ * Get connection
+ * @method
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @return {Connection}
+ */
+Mongos.prototype.getConnection = function(options) {
+  // Ensure we have no options
+  options = options || {};
+  // Pick the right server based on readPreference
+  var server = this.s.mongosState.pickServer(options.readPreference);
+  if(server == null) return null;
+  // Return connection
+  return server.getConnection();
+}
+
+/**
+ * Get server
+ * @method
+ * @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
+ * @return {Server}
+ */
+Mongos.prototype.getServer = function(options) {
+  // Ensure we have no options
+  options = options || {};
+  // Pick the right server based on readPreference
+  return this.s.mongosState.pickServer(options.readPreference);
+}
+
+/**
+ * All raw connections
+ * @method
+ * @return {Connection[]}
+ */
+Mongos.prototype.connections = function() {
+  return this.s.mongosState.getAllConnections();
+}
+
+//
+// Inquires about state changes
+//
+var mongosInquirer = function(self, state) {    
+  return function() {
+    if(state.state == DESTROYED) return
+    if(state.state == CONNECTED) state.retriesLeft = state.reconnectTries;
+
+    // If we have a disconnected site
+    if(state.state == DISCONNECTED && state.retriesLeft == 0) {
+      self.destroy();
+      return self.emit('error', new MongoError(f('failed to reconnect after %s', state.reconnectTries)));
+    } else if(state == DISCONNECTED) {
+      state.retriesLeft = state.retriesLeft - 1;
+    }
+
+    // If we have a primary and a disconnect handler, execute
+    // buffered operations
+    if(state.mongosState.isConnected() && state.disconnectHandler) {
+      state.disconnectHandler.execute();
+    }
+
+    // Log the information
+    if(state.logger.isDebug()) state.logger.debug(f('mongos ha proceess running'));
+    
+    // Let's query any disconnected proxies
+    var disconnectedServers = state.mongosState.disconnectedServers();
+    if(disconnectedServers.length == 0) return setTimeout(mongosInquirer(self, state), state.haInterval);
+    
+    // Count of connections waiting to be connected
+    var connectionCount = disconnectedServers.length;
+    if(state.logger.isDebug()) state.logger.debug(f('mongos ha proceess found %d disconnected proxies', connectionCount));
+    
+    // Let's attempt to reconnect
+    while(disconnectedServers.length > 0) {
+      var server = disconnectedServers.shift();
+      if(state.logger.isDebug()) state.logger.debug(f('attempting to connect to server %s', server.name));
+
+      // Remove any listeners
+      ['error', 'close', 'timeout', 'connect', 'message', 'parseError'].forEach(function(e) {
+        server.removeAllListeners(e);
+      });
+  
+      // Set up the event handlers
+      server.once('error', errorHandlerTemp(self, state, server));
+      server.once('close', errorHandlerTemp(self, state, server));
+      server.once('timeout', errorHandlerTemp(self, state, server));
+      server.once('connect', connectHandler(self, state, 'ha'));
+      // Start connect
+      server.connect();
+    }
+
+    // Let's keep monitoring but wait for possible timeout to happen
+    return setTimeout(mongosInquirer(self, state), state.options.connectionTimeout + state.haInterval);      
+  }
+}
+
+//
+// Error handler for initial connect
+var errorHandlerTemp = function(self, state, server) {
+  return function(err, server) {
+    // Log the information
+    if(state.logger.isInfo()) state.logger.info(f('server %s disconnected with error %s',  server.name, JSON.stringify(err)));
+
+    // Remove any non used handlers
+    ['error', 'close', 'timeout', 'connect'].forEach(function(e) {
+      server.removeAllListeners(e);
+    })
+
+    // Signal disconnect of server
+    state.mongosState.disconnected(server);
+  }
+}
+
+//
+// Handlers
+var errorHandler = function(self, state) {
+  return function(err, server) {
+    if(state.logger.isInfo()) state.logger.info(f('server %s errored out with %s', server.name, JSON.stringify(err)));
+    state.mongosState.disconnected(server);
+    // No more servers left emit close
+    if(state.mongosState.connectedServers().length == 0) {
+      state.state = DISCONNECTED;
+    }
+
+    // Signal server left
+    self.emit('left', 'mongos', server);    
+    if(state.emitError) self.emit('error', err, server);
+  }
+}
+
+var timeoutHandler = function(self, state) {
+  return function(err, server) {
+    if(state.logger.isInfo()) state.logger.info(f('server %s timed out', server.name));
+    state.mongosState.disconnected(server);
+
+    // No more servers emit close event if no entries left
+    if(state.mongosState.connectedServers().length == 0) {
+      state.state = DISCONNECTED;
+    }
+
+    // Signal server left
+    self.emit('left', 'mongos', server);
+  }
+}
+
+var closeHandler = function(self, state) {
+  return function(err, server) {
+    if(state.logger.isInfo()) state.logger.info(f('server %s closed', server.name));
+    state.mongosState.disconnected(server);
+
+    // No more servers left emit close
+    if(state.mongosState.connectedServers().length == 0) {
+      state.state = DISCONNECTED;
+    }
+
+    // Signal server left
+    self.emit('left', 'mongos', server);
+  }
+}
+
+// Connect handler
+var connectHandler = function(self, state, e) {
+  return function(server) {
+    if(state.logger.isInfo()) state.logger.info(f('connected to %s', server.name));
+
+    // Remove any non used handlers
+    ['error', 'close', 'timeout', 'connect', 'message', 'parseError'].forEach(function(e) {
+      server.removeAllListeners(e);
+    });
+
+    // finish processing the server
+    var processNewServer = function(_server) {
+      // Add the server handling code
+      if(_server.isConnected()) {
+        _server.once('error', errorHandler(self, state));
+        _server.once('close', closeHandler(self, state));
+        _server.once('timeout', timeoutHandler(self, state));
+        _server.once('parseError', timeoutHandler(self, state));
+      }
+
+      // Emit joined event
+      self.emit('joined', 'mongos', _server);
+
+      // Add to list connected servers
+      state.mongosState.connected(_server);
+
+      // Do we have a reconnect event
+      if('ha' == e && state.mongosState.connectedServers().length == 1) {
+        self.emit('reconnect', _server);
+      }
+
+      // Full setup
+      if(state.mongosState.disconnectedServers().length == 0 && 
+        state.mongosState.connectedServers().length > 0 &&
+        !state.fullsetup) {
+        state.fullsetup = true;
+        self.emit('fullsetup');
+      }
+
+      // all connected
+      if(state.mongosState.disconnectedServers().length == 0 && 
+        state.mongosState.connectedServers().length == state.seedlist.length &&
+        !state.all) {
+        state.all = true;
+        self.emit('all');
+      }
+
+      // Set connected
+      if(state.state == DISCONNECTED) {
+        state.state = CONNECTED;
+        self.emit('connect', self);
+      }
+    }
+
+    // Is there an authentication process ongoing
+    if(state.authInProgress) {
+      state.authInProgressServers.push(server);
+    }
+
+    // No credentials just process server
+    if(state.credentials.length == 0) return processNewServer(server);
+
+    // Do we have credentials, let's apply them all
+    var count = state.credentials.length;
+    // Apply the credentials
+    for(var i = 0; i < state.credentials.length; i++) {
+      server.auth.apply(server, state.credentials[i].concat([function(err, r) {        
+        count = count - 1;
+        if(count == 0) processNewServer(server);
+      }]));
+    }
+  }
+}
+
+//
+// Add server to the list if it does not exist
+var addToListIfNotExist = function(list, server) {
+  var found = false;
+
+  // Remove any non used handlers
+  ['error', 'close', 'timeout', 'connect'].forEach(function(e) {
+    server.removeAllListeners(e);
+  })
+
+  // Check if the server already exists
+  for(var i = 0; i < list.length; i++) {
+    if(list[i].equals(server)) found = true;
+  }
+
+  if(!found) {
+    list.push(server);
+  }
+}
+
+// Add the new credential for a db, removing the old
+// credential from the cache
+var addCredentials = function(state, db, argsWithoutCallback) {
+  // Remove any credentials for the db
+  clearCredentials(state, db + ".dummy");
+  // Add new credentials to list
+  state.credentials.push(argsWithoutCallback);
+}
+
+// Clear out credentials for a namespace
+var clearCredentials = function(state, ns) {
+  var db = ns.split('.')[0];
+  var filteredCredentials = [];
+
+  // Filter out all credentials for the db the user is logging out off
+  for(var i = 0; i < state.credentials.length; i++) {
+    if(state.credentials[i][1] != db) filteredCredentials.push(state.credentials[i]);
+  }
+
+  // Set new list of credentials
+  state.credentials = filteredCredentials;
+}
+
+var processReadPreference = function(cmd, options) {
+  options = options || {}
+  // No read preference specified
+  if(options.readPreference == null) return cmd;
+}
+
+//
+// Execute write operation
+var executeWriteOperation = function(state, op, ns, ops, options, callback) {
+  if(typeof options == 'function') {
+    callback = options;
+    options = {};
+  }
+
+  var server = null;
+  // Ensure we have no options
+  options = options || {};
+  try {
+    // Get a primary   
+    server = state.mongosState.pickServer();
+  } catch(err) {
+    return callback(err);
+  }
+
+  // No server returned we had an error
+  if(server == null) return callback(new MongoError("no mongos found"));
+  // Execute the command
+  server[op](ns, ops, options, callback);          
+}
+
+/**
+ * A mongos connect event, used to verify that the connection is up and running
+ *
+ * @event Mongos#connect
+ * @type {Mongos}
+ */
+
+/**
+ * A server member left the mongos list
+ *
+ * @event Mongos#left
+ * @type {Mongos}
+ * @param {string} type The type of member that left (mongos)
+ * @param {Server} server The server object that left
+ */
+
+/**
+ * A server member joined the mongos list
+ *
+ * @event Mongos#joined
+ * @type {Mongos}
+ * @param {string} type The type of member that left (mongos)
+ * @param {Server} server The server object that joined
+ */
+
+module.exports = Mongos;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/couchdb-nmo/blob/753f1767/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/read_preference.js
----------------------------------------------------------------------
diff --git a/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/read_preference.js b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/read_preference.js
new file mode 100644
index 0000000..913ca1b
--- /dev/null
+++ b/node_modules/couchbulkimporter/node_modules/mongodb/node_modules/mongodb-core/lib/topologies/read_preference.js
@@ -0,0 +1,106 @@
+"use strict";
+
+var needSlaveOk = ['primaryPreferred', 'secondary', 'secondaryPreferred', 'nearest'];
+
+/**
+ * @fileOverview The **ReadPreference** class is a class that represents a MongoDB ReadPreference and is
+ * used to construct connections.
+ * 
+ * @example
+ * var ReplSet = require('mongodb-core').ReplSet
+ *   , ReadPreference = require('mongodb-core').ReadPreference
+ *   , assert = require('assert');
+ * 
+ * var server = new ReplSet([{host: 'localhost', port: 30000}], {setName: 'rs'});
+ * // Wait for the connection event
+ * server.on('connect', function(server) {
+ *   var cursor = server.cursor('db.test'
+ *     , {find: 'db.test', query: {}}
+ *     , {readPreference: new ReadPreference('secondary')});
+ *   cursor.next(function(err, doc) {
+ *     server.destroy();
+ *   });
+ * });
+ * 
+ * // Start connecting
+ * server.connect();
+ */
+
+/**
+ * Creates a new Pool instance
+ * @class
+ * @param {string} preference A string describing the preference (primary|primaryPreferred|secondary|secondaryPreferred|nearest)
+ * @param {object} tags The tags object
+ * @param {object} [options] Additional read preference options
+ * @property {string} preference The preference string (primary|primaryPreferred|secondary|secondaryPreferred|nearest)
+ * @property {object} tags The tags object
+ * @property {object} options Additional read preference options
+ * @return {ReadPreference}
+ */
+var ReadPreference = function(preference, tags, options) {
+  this.preference = preference;
+  this.tags = tags;
+  this.options = options;
+}
+
+/**
+ * This needs slaveOk bit set
+ * @method
+ * @return {boolean}
+ */
+ReadPreference.prototype.slaveOk = function() {
+  return needSlaveOk.indexOf(this.preference) != -1;
+}
+
+/**
+ * Are the two read preference equal
+ * @method
+ * @return {boolean}
+ */
+ReadPreference.prototype.equals = function(readPreference) {
+  return readPreference.preference == this.preference;
+}
+
+/**
+ * Return JSON representation
+ * @method
+ * @return {Object}
+ */
+ReadPreference.prototype.toJSON = function() {
+  var readPreference = {mode: this.preference};
+  if(Array.isArray(this.tags)) readPreference.tags = this.tags;
+  return readPreference;
+}
+
+/**
+ * Primary read preference
+ * @method
+ * @return {ReadPreference}
+ */
+ReadPreference.primary = new ReadPreference('primary');
+/**
+ * Primary Preferred read preference
+ * @method
+ * @return {ReadPreference}
+ */
+ReadPreference.primaryPreferred = new ReadPreference('primaryPreferred');
+/**
+ * Secondary read preference
+ * @method
+ * @return {ReadPreference}
+ */
+ReadPreference.secondary = new ReadPreference('secondary');
+/**
+ * Secondary Preferred read preference
+ * @method
+ * @return {ReadPreference}
+ */
+ReadPreference.secondaryPreferred = new ReadPreference('secondaryPreferred');
+/**
+ * Nearest read preference
+ * @method
+ * @return {ReadPreference}
+ */
+ReadPreference.nearest = new ReadPreference('nearest');
+
+module.exports = ReadPreference;
\ No newline at end of file


Mime
View raw message