PageRenderTime 28ms CodeModel.GetById 9ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

/node_modules/mongodb-core/lib/topologies/shared.js

https://bitbucket.org/coleman333/smartsite
JavaScript | 334 lines | 242 code | 52 blank | 40 comment | 53 complexity | 79a8f638645d81efaa8de33f1b15dd57 MD5 | raw file
  1"use strict"
  2
  3var os = require('os'),
  4  f = require('util').format;
  5
  6/**
  7 * Emit event if it exists
  8 * @method
  9 */
 10function emitSDAMEvent(self, event, description) {
 11  if(self.listeners(event).length > 0) {
 12    self.emit(event, description);
 13  }
 14}
 15
 16// Get package.json variable
 17var driverVersion = require('../../package.json').version;
 18var nodejsversion = f('Node.js %s, %s', process.version, os.endianness());
 19var type = os.type();
 20var name = process.platform;
 21var architecture = process.arch;
 22var release = os.release();
 23
 24function createClientInfo(options) {
 25  // Build default client information
 26  var clientInfo = options.clientInfo ? clone(options.clientInfo) : {
 27    driver: {
 28      name: "nodejs-core",
 29      version: driverVersion
 30    },
 31    os: {
 32      type: type,
 33      name: name,
 34      architecture: architecture,
 35      version: release
 36    }
 37  }
 38
 39  // Is platform specified
 40  if(clientInfo.platform && clientInfo.platform.indexOf('mongodb-core') == -1) {
 41    clientInfo.platform = f('%s, mongodb-core: %s', clientInfo.platform, driverVersion);
 42  } else if(!clientInfo.platform){
 43    clientInfo.platform = nodejsversion;
 44  }
 45
 46  // Do we have an application specific string
 47  if(options.appname) {
 48    // Cut at 128 bytes
 49    var buffer = new Buffer(options.appname);
 50    // Return the truncated appname
 51    var appname = buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname;
 52    // Add to the clientInfo
 53    clientInfo.application = { name: appname };
 54  }
 55
 56  return clientInfo;
 57}
 58
 59function clone(object) {
 60  return JSON.parse(JSON.stringify(object));
 61}
 62
 63var getPreviousDescription = function(self) {
 64  if(!self.s.serverDescription) {
 65    self.s.serverDescription = {
 66      address: self.name,
 67      arbiters: [], hosts: [], passives: [], type: 'Unknown'
 68    }
 69  }
 70
 71  return self.s.serverDescription;
 72}
 73
 74var emitServerDescriptionChanged = function(self, description) {
 75  if(self.listeners('serverDescriptionChanged').length > 0) {
 76    // Emit the server description changed events
 77    self.emit('serverDescriptionChanged', {
 78      topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id, address: self.name,
 79      previousDescription: getPreviousDescription(self),
 80      newDescription: description
 81    });
 82
 83    self.s.serverDescription = description;
 84  }
 85}
 86
 87var getPreviousTopologyDescription = function(self) {
 88  if(!self.s.topologyDescription) {
 89    self.s.topologyDescription = {
 90      topologyType: 'Unknown',
 91      servers: [{
 92        address: self.name, arbiters: [], hosts: [], passives: [], type: 'Unknown'
 93      }]
 94    }
 95  }
 96
 97  return self.s.topologyDescription;
 98}
 99
100var emitTopologyDescriptionChanged = function(self, description) {
101  if(self.listeners('topologyDescriptionChanged').length > 0) {
102    // Emit the server description changed events
103    self.emit('topologyDescriptionChanged', {
104      topologyId: self.s.topologyId != -1 ? self.s.topologyId : self.id, address: self.name,
105      previousDescription: getPreviousTopologyDescription(self),
106      newDescription: description
107    });
108
109    self.s.serverDescription = description;
110  }
111}
112
113var changedIsMaster = function(self, currentIsmaster, ismaster) {
114  var currentType = getTopologyType(self, currentIsmaster);
115  var newType = getTopologyType(self, ismaster);
116  if(newType != currentType) return true;
117  return false;
118}
119
120var getTopologyType = function(self, ismaster) {
121  if(!ismaster) {
122    ismaster = self.ismaster;
123  }
124
125  if(!ismaster) return 'Unknown';
126  if(ismaster.ismaster && ismaster.msg == 'isdbgrid') return 'Mongos';
127  if(ismaster.ismaster && !ismaster.hosts) return 'Standalone';
128  if(ismaster.ismaster) return 'RSPrimary';
129  if(ismaster.secondary) return 'RSSecondary';
130  if(ismaster.arbiterOnly) return 'RSArbiter';
131  return 'Unknown';
132}
133
134var inquireServerState = function(self) {
135  return function(callback) {
136    if(self.s.state == 'destroyed') return;
137    // Record response time
138    var start = new Date().getTime();
139
140    // emitSDAMEvent
141    emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: self.name });
142
143    // Attempt to execute ismaster command
144    self.command('admin.$cmd', { ismaster:true },  { monitoring:true }, function(err, r) {
145      if(!err) {
146        // Legacy event sender
147        self.emit('ismaster', r, self);
148
149        // Calculate latencyMS
150        var latencyMS = new Date().getTime() - start;
151
152        // Server heart beat event
153        emitSDAMEvent(self, 'serverHeartbeatSucceeded', { durationMS: latencyMS, reply: r.result, connectionId: self.name });
154
155        // Did the server change
156        if(changedIsMaster(self, self.s.ismaster, r.result)) {
157          // Emit server description changed if something listening
158          emitServerDescriptionChanged(self, {
159            address: self.name, arbiters: [], hosts: [], passives: [], type: !self.s.inTopology ? 'Standalone' : getTopologyType(self)
160          });
161        }
162
163        // Updat ismaster view
164        self.s.ismaster = r.result;
165
166        // Set server response time
167        self.s.isMasterLatencyMS = latencyMS;
168      } else {
169        emitSDAMEvent(self, 'serverHeartbeatFailed', { durationMS: latencyMS, failure: err, connectionId: self.name });
170      }
171
172      // Peforming an ismaster monitoring callback operation
173      if(typeof callback == 'function') {
174        return callback(err, r);
175      }
176
177      // Perform another sweep
178      self.s.inquireServerStateTimeout = setTimeout(inquireServerState(self), self.s.haInterval);
179    });
180  };
181}
182
183//
184// Clone the options
185var cloneOptions = function(options) {
186  var opts = {};
187  for(var name in options) {
188    opts[name] = options[name];
189  }
190  return opts;
191}
192
193function Interval(fn, time) {
194  var timer = false;
195
196  this.start = function () {
197    if (!this.isRunning()) {
198      timer = setInterval(fn, time);
199    }
200
201    return this;
202  };
203
204  this.stop = function () {
205    clearInterval(timer);
206    timer = false;
207    return this;
208  };
209
210  this.isRunning = function () {
211    return timer !== false;
212  };
213}
214
215function Timeout(fn, time) {
216  var timer = false;
217
218  this.start = function () {
219    if (!this.isRunning()) {
220      timer = setTimeout(function() {
221        fn();
222        if (timer && timer._called === undefined) {
223          // The artificial _called is set here for compatibility with node.js 0.10.x/0.12.x versions
224          timer._called = true;
225        }
226      }, time);
227    }
228    return this;
229  };
230
231  this.stop = function () {
232    clearTimeout(timer);
233    timer = false;
234    return this;
235  };
236
237  this.isRunning = function () {
238    if(timer && timer._called) return false;
239    return timer !== false;
240  };
241}
242
243function diff(previous, current) {
244  // Difference document
245  var diff = {
246    servers: []
247  }
248
249  // Previous entry
250  if(!previous) {
251    previous = { servers: [] };
252  }
253
254  // Check if we have any previous servers missing in the current ones
255  for(var i = 0; i < previous.servers.length; i++) {
256    var found = false;
257
258    for(var j = 0; j < current.servers.length; j++) {
259      if(current.servers[j].address.toLowerCase()
260        === previous.servers[i].address.toLowerCase()) {
261          found = true;
262          break;
263        }
264    }
265
266    if(!found) {
267      // Add to the diff
268      diff.servers.push({
269        address: previous.servers[i].address,
270        from: previous.servers[i].type,
271        to: 'Unknown',
272      });
273    }
274  }
275
276  // Check if there are any severs that don't exist
277  for(var j = 0; j < current.servers.length; j++) {
278    var found = false;
279
280    // Go over all the previous servers
281    for(var i = 0; i < previous.servers.length; i++) {
282      if(previous.servers[i].address.toLowerCase()
283        === current.servers[j].address.toLowerCase()) {
284        found = true;
285        break;
286      }
287    }
288
289    // Add the server to the diff
290    if(!found) {
291      diff.servers.push({
292        address: current.servers[j].address,
293        from: 'Unknown',
294        to: current.servers[j].type,
295      });
296    }
297  }
298
299  // Got through all the servers
300  for(var i = 0; i < previous.servers.length; i++) {
301    var prevServer = previous.servers[i];
302
303    // Go through all current servers
304    for(var j = 0; j < current.servers.length; j++) {
305      var currServer = current.servers[j];
306
307      // Matching server
308      if(prevServer.address.toLowerCase() === currServer.address.toLowerCase()) {
309        // We had a change in state
310        if(prevServer.type != currServer.type) {
311          diff.servers.push({
312            address: prevServer.address,
313            from: prevServer.type,
314            to: currServer.type
315          });
316        }
317      }
318    }
319  }
320
321  // Return difference
322  return diff;
323}
324
325module.exports.inquireServerState = inquireServerState
326module.exports.getTopologyType = getTopologyType;
327module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged;
328module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged;
329module.exports.cloneOptions = cloneOptions;
330module.exports.createClientInfo = createClientInfo;
331module.exports.clone = clone;
332module.exports.diff = diff;
333module.exports.Interval = Interval;
334module.exports.Timeout = Timeout;