mongodb 3.2.5 → 3.3.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +0 -10
- package/index.js +4 -4
- package/lib/admin.js +56 -56
- package/lib/aggregation_cursor.js +7 -3
- package/lib/bulk/common.js +18 -13
- package/lib/change_stream.js +196 -89
- package/lib/collection.js +217 -169
- package/lib/command_cursor.js +17 -7
- package/lib/core/auth/auth_provider.js +158 -0
- package/lib/core/auth/defaultAuthProviders.js +29 -0
- package/lib/core/auth/gssapi.js +241 -0
- package/lib/core/auth/mongo_credentials.js +81 -0
- package/lib/core/auth/mongocr.js +51 -0
- package/lib/core/auth/plain.js +35 -0
- package/lib/core/auth/scram.js +293 -0
- package/lib/core/auth/sspi.js +131 -0
- package/lib/core/auth/x509.js +26 -0
- package/lib/core/connection/apm.js +236 -0
- package/lib/core/connection/command_result.js +36 -0
- package/lib/core/connection/commands.js +507 -0
- package/lib/core/connection/connect.js +370 -0
- package/lib/core/connection/connection.js +624 -0
- package/lib/core/connection/logger.js +246 -0
- package/lib/core/connection/msg.js +219 -0
- package/lib/core/connection/pool.js +1285 -0
- package/lib/core/connection/utils.js +57 -0
- package/lib/core/cursor.js +752 -0
- package/lib/core/error.js +186 -0
- package/lib/core/index.js +50 -0
- package/lib/core/sdam/monitoring.js +228 -0
- package/lib/core/sdam/server.js +467 -0
- package/lib/core/sdam/server_description.js +163 -0
- package/lib/core/sdam/server_selectors.js +244 -0
- package/lib/core/sdam/srv_polling.js +135 -0
- package/lib/core/sdam/topology.js +1151 -0
- package/lib/core/sdam/topology_description.js +408 -0
- package/lib/core/sessions.js +711 -0
- package/lib/core/tools/smoke_plugin.js +61 -0
- package/lib/core/topologies/mongos.js +1337 -0
- package/lib/core/topologies/read_preference.js +202 -0
- package/lib/core/topologies/replset.js +1507 -0
- package/lib/core/topologies/replset_state.js +1121 -0
- package/lib/core/topologies/server.js +984 -0
- package/lib/core/topologies/shared.js +453 -0
- package/lib/core/transactions.js +167 -0
- package/lib/core/uri_parser.js +631 -0
- package/lib/core/utils.js +165 -0
- package/lib/core/wireprotocol/command.js +170 -0
- package/lib/core/wireprotocol/compression.js +73 -0
- package/lib/core/wireprotocol/constants.js +13 -0
- package/lib/core/wireprotocol/get_more.js +86 -0
- package/lib/core/wireprotocol/index.js +18 -0
- package/lib/core/wireprotocol/kill_cursors.js +70 -0
- package/lib/core/wireprotocol/query.js +224 -0
- package/lib/core/wireprotocol/shared.js +115 -0
- package/lib/core/wireprotocol/write_command.js +50 -0
- package/lib/cursor.js +40 -46
- package/lib/db.js +141 -95
- package/lib/dynamic_loaders.js +32 -0
- package/lib/error.js +12 -10
- package/lib/gridfs/chunk.js +2 -2
- package/lib/gridfs/grid_store.js +31 -25
- package/lib/gridfs-stream/index.js +4 -4
- package/lib/gridfs-stream/upload.js +1 -1
- package/lib/mongo_client.js +37 -15
- package/lib/operations/add_user.js +96 -0
- package/lib/operations/aggregate.js +24 -13
- package/lib/operations/aggregate_operation.js +127 -0
- package/lib/operations/bulk_write.js +104 -0
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +28 -287
- package/lib/operations/collections.js +55 -0
- package/lib/operations/command.js +120 -0
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/common_functions.js +372 -0
- package/lib/operations/{mongo_client_ops.js → connect.js} +185 -157
- package/lib/operations/count.js +72 -0
- package/lib/operations/count_documents.js +46 -0
- package/lib/operations/create_collection.js +118 -0
- package/lib/operations/create_index.js +92 -0
- package/lib/operations/create_indexes.js +61 -0
- package/lib/operations/cursor_ops.js +3 -4
- package/lib/operations/db_ops.js +15 -12
- package/lib/operations/delete_many.js +25 -0
- package/lib/operations/delete_one.js +25 -0
- package/lib/operations/distinct.js +85 -0
- package/lib/operations/drop.js +53 -0
- package/lib/operations/drop_index.js +42 -0
- package/lib/operations/drop_indexes.js +23 -0
- package/lib/operations/estimated_document_count.js +33 -0
- package/lib/operations/execute_db_admin_command.js +34 -0
- package/lib/operations/execute_operation.js +165 -0
- package/lib/operations/explain.js +23 -0
- package/lib/operations/find_and_modify.js +98 -0
- package/lib/operations/find_one.js +33 -0
- package/lib/operations/find_one_and_delete.js +16 -0
- package/lib/operations/find_one_and_replace.js +18 -0
- package/lib/operations/find_one_and_update.js +19 -0
- package/lib/operations/geo_haystack_search.js +79 -0
- package/lib/operations/has_next.js +40 -0
- package/lib/operations/index_exists.js +39 -0
- package/lib/operations/index_information.js +23 -0
- package/lib/operations/indexes.js +22 -0
- package/lib/operations/insert_many.js +63 -0
- package/lib/operations/insert_one.js +75 -0
- package/lib/operations/is_capped.js +19 -0
- package/lib/operations/list_indexes.js +66 -0
- package/lib/operations/map_reduce.js +189 -0
- package/lib/operations/next.js +32 -0
- package/lib/operations/operation.js +63 -0
- package/lib/operations/options_operation.js +32 -0
- package/lib/operations/profiling_level.js +31 -0
- package/lib/operations/re_index.js +28 -0
- package/lib/operations/remove_user.js +52 -0
- package/lib/operations/rename.js +61 -0
- package/lib/operations/replace_one.js +47 -0
- package/lib/operations/set_profiling_level.js +48 -0
- package/lib/operations/stats.js +45 -0
- package/lib/operations/to_array.js +68 -0
- package/lib/operations/update_many.js +29 -0
- package/lib/operations/update_one.js +44 -0
- package/lib/operations/validate_collection.js +40 -0
- package/lib/read_concern.js +55 -0
- package/lib/topologies/mongos.js +3 -3
- package/lib/topologies/native_topology.js +22 -2
- package/lib/topologies/replset.js +3 -3
- package/lib/topologies/server.js +4 -4
- package/lib/topologies/topology_base.js +6 -6
- package/lib/url_parser.js +4 -3
- package/lib/utils.js +46 -59
- package/lib/write_concern.js +66 -0
- package/package.json +15 -6
- package/lib/.DS_Store +0 -0
|
@@ -0,0 +1,1337 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const inherits = require('util').inherits;
|
|
4
|
+
const f = require('util').format;
|
|
5
|
+
const EventEmitter = require('events').EventEmitter;
|
|
6
|
+
const BasicCursor = require('../cursor');
|
|
7
|
+
const Logger = require('../connection/logger');
|
|
8
|
+
const retrieveBSON = require('../connection/utils').retrieveBSON;
|
|
9
|
+
const MongoError = require('../error').MongoError;
|
|
10
|
+
const Server = require('./server');
|
|
11
|
+
const clone = require('./shared').clone;
|
|
12
|
+
const diff = require('./shared').diff;
|
|
13
|
+
const cloneOptions = require('./shared').cloneOptions;
|
|
14
|
+
const createClientInfo = require('./shared').createClientInfo;
|
|
15
|
+
const SessionMixins = require('./shared').SessionMixins;
|
|
16
|
+
const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported;
|
|
17
|
+
const relayEvents = require('../utils').relayEvents;
|
|
18
|
+
const isRetryableError = require('../error').isRetryableError;
|
|
19
|
+
const BSON = retrieveBSON();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is
|
|
23
|
+
* used to construct connections.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
//
|
|
27
|
+
// States
|
|
28
|
+
var DISCONNECTED = 'disconnected';
|
|
29
|
+
var CONNECTING = 'connecting';
|
|
30
|
+
var CONNECTED = 'connected';
|
|
31
|
+
var UNREFERENCED = 'unreferenced';
|
|
32
|
+
var DESTROYED = 'destroyed';
|
|
33
|
+
|
|
34
|
+
function stateTransition(self, newState) {
|
|
35
|
+
var legalTransitions = {
|
|
36
|
+
disconnected: [CONNECTING, DESTROYED, DISCONNECTED],
|
|
37
|
+
connecting: [CONNECTING, DESTROYED, CONNECTED, DISCONNECTED],
|
|
38
|
+
connected: [CONNECTED, DISCONNECTED, DESTROYED, UNREFERENCED],
|
|
39
|
+
unreferenced: [UNREFERENCED, DESTROYED],
|
|
40
|
+
destroyed: [DESTROYED]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Get current state
|
|
44
|
+
var legalStates = legalTransitions[self.state];
|
|
45
|
+
if (legalStates && legalStates.indexOf(newState) !== -1) {
|
|
46
|
+
self.state = newState;
|
|
47
|
+
} else {
|
|
48
|
+
self.logger.error(
|
|
49
|
+
f(
|
|
50
|
+
'Pool with id [%s] failed attempted illegal state transition from [%s] to [%s] only following state allowed [%s]',
|
|
51
|
+
self.id,
|
|
52
|
+
self.state,
|
|
53
|
+
newState,
|
|
54
|
+
legalStates
|
|
55
|
+
)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//
|
|
61
|
+
// ReplSet instance id
|
|
62
|
+
var id = 1;
|
|
63
|
+
var handlers = ['connect', 'close', 'error', 'timeout', 'parseError'];
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Creates a new Mongos instance
|
|
67
|
+
* @class
|
|
68
|
+
* @param {array} seedlist A list of seeds for the replicaset
|
|
69
|
+
* @param {number} [options.haInterval=5000] The High availability period for replicaset inquiry
|
|
70
|
+
* @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
|
|
71
|
+
* @param {number} [options.size=5] Server connection pool size
|
|
72
|
+
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
|
73
|
+
* @param {number} [options.keepAliveInitialDelay=0] Initial delay before TCP keep alive enabled
|
|
74
|
+
* @param {number} [options.localThresholdMS=15] Cutoff latency point in MS for MongoS proxy selection
|
|
75
|
+
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
|
76
|
+
* @param {number} [options.connectionTimeout=1000] TCP Connection timeout setting
|
|
77
|
+
* @param {number} [options.socketTimeout=0] TCP Socket timeout setting
|
|
78
|
+
* @param {boolean} [options.ssl=false] Use SSL for connection
|
|
79
|
+
* @param {boolean|function} [options.checkServerIdentity=true] Ensure we check server identify during SSL, set to false to disable checking. Only works for Node 0.12.x or higher. You can pass in a boolean or your own checkServerIdentity override function.
|
|
80
|
+
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
|
|
81
|
+
* @param {Buffer} [options.crl] SSL Certificate revocation store binary buffer
|
|
82
|
+
* @param {Buffer} [options.cert] SSL Certificate binary buffer
|
|
83
|
+
* @param {Buffer} [options.key] SSL Key file binary buffer
|
|
84
|
+
* @param {string} [options.passphrase] SSL Certificate pass phrase
|
|
85
|
+
* @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
|
|
86
|
+
* @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
|
|
87
|
+
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
|
88
|
+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
89
|
+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
90
|
+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
|
91
|
+
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
|
92
|
+
* @return {Mongos} A cursor instance
|
|
93
|
+
* @fires Mongos#connect
|
|
94
|
+
* @fires Mongos#reconnect
|
|
95
|
+
* @fires Mongos#joined
|
|
96
|
+
* @fires Mongos#left
|
|
97
|
+
* @fires Mongos#failed
|
|
98
|
+
* @fires Mongos#fullsetup
|
|
99
|
+
* @fires Mongos#all
|
|
100
|
+
* @fires Mongos#serverHeartbeatStarted
|
|
101
|
+
* @fires Mongos#serverHeartbeatSucceeded
|
|
102
|
+
* @fires Mongos#serverHeartbeatFailed
|
|
103
|
+
* @fires Mongos#topologyOpening
|
|
104
|
+
* @fires Mongos#topologyClosed
|
|
105
|
+
* @fires Mongos#topologyDescriptionChanged
|
|
106
|
+
* @property {string} type the topology type.
|
|
107
|
+
* @property {string} parserType the parser type used (c++ or js).
|
|
108
|
+
*/
|
|
109
|
+
var Mongos = function(seedlist, options) {
|
|
110
|
+
options = options || {};
|
|
111
|
+
|
|
112
|
+
// Get replSet Id
|
|
113
|
+
this.id = id++;
|
|
114
|
+
|
|
115
|
+
// Internal state
|
|
116
|
+
this.s = {
|
|
117
|
+
options: Object.assign({}, options),
|
|
118
|
+
// BSON instance
|
|
119
|
+
bson:
|
|
120
|
+
options.bson ||
|
|
121
|
+
new BSON([
|
|
122
|
+
BSON.Binary,
|
|
123
|
+
BSON.Code,
|
|
124
|
+
BSON.DBRef,
|
|
125
|
+
BSON.Decimal128,
|
|
126
|
+
BSON.Double,
|
|
127
|
+
BSON.Int32,
|
|
128
|
+
BSON.Long,
|
|
129
|
+
BSON.Map,
|
|
130
|
+
BSON.MaxKey,
|
|
131
|
+
BSON.MinKey,
|
|
132
|
+
BSON.ObjectId,
|
|
133
|
+
BSON.BSONRegExp,
|
|
134
|
+
BSON.Symbol,
|
|
135
|
+
BSON.Timestamp
|
|
136
|
+
]),
|
|
137
|
+
// Factory overrides
|
|
138
|
+
Cursor: options.cursorFactory || BasicCursor,
|
|
139
|
+
// Logger instance
|
|
140
|
+
logger: Logger('Mongos', options),
|
|
141
|
+
// Seedlist
|
|
142
|
+
seedlist: seedlist,
|
|
143
|
+
// Ha interval
|
|
144
|
+
haInterval: options.haInterval ? options.haInterval : 10000,
|
|
145
|
+
// Disconnect handler
|
|
146
|
+
disconnectHandler: options.disconnectHandler,
|
|
147
|
+
// Server selection index
|
|
148
|
+
index: 0,
|
|
149
|
+
// Connect function options passed in
|
|
150
|
+
connectOptions: {},
|
|
151
|
+
// Are we running in debug mode
|
|
152
|
+
debug: typeof options.debug === 'boolean' ? options.debug : false,
|
|
153
|
+
// localThresholdMS
|
|
154
|
+
localThresholdMS: options.localThresholdMS || 15,
|
|
155
|
+
// Client info
|
|
156
|
+
clientInfo: createClientInfo(options)
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Set the client info
|
|
160
|
+
this.s.options.clientInfo = createClientInfo(options);
|
|
161
|
+
|
|
162
|
+
// Log info warning if the socketTimeout < haInterval as it will cause
|
|
163
|
+
// a lot of recycled connections to happen.
|
|
164
|
+
if (
|
|
165
|
+
this.s.logger.isWarn() &&
|
|
166
|
+
this.s.options.socketTimeout !== 0 &&
|
|
167
|
+
this.s.options.socketTimeout < this.s.haInterval
|
|
168
|
+
) {
|
|
169
|
+
this.s.logger.warn(
|
|
170
|
+
f(
|
|
171
|
+
'warning socketTimeout %s is less than haInterval %s. This might cause unnecessary server reconnections due to socket timeouts',
|
|
172
|
+
this.s.options.socketTimeout,
|
|
173
|
+
this.s.haInterval
|
|
174
|
+
)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Disconnected state
|
|
179
|
+
this.state = DISCONNECTED;
|
|
180
|
+
|
|
181
|
+
// Current proxies we are connecting to
|
|
182
|
+
this.connectingProxies = [];
|
|
183
|
+
// Currently connected proxies
|
|
184
|
+
this.connectedProxies = [];
|
|
185
|
+
// Disconnected proxies
|
|
186
|
+
this.disconnectedProxies = [];
|
|
187
|
+
// Index of proxy to run operations against
|
|
188
|
+
this.index = 0;
|
|
189
|
+
// High availability timeout id
|
|
190
|
+
this.haTimeoutId = null;
|
|
191
|
+
// Last ismaster
|
|
192
|
+
this.ismaster = null;
|
|
193
|
+
|
|
194
|
+
// Description of the Replicaset
|
|
195
|
+
this.topologyDescription = {
|
|
196
|
+
topologyType: 'Unknown',
|
|
197
|
+
servers: []
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Highest clusterTime seen in responses from the current deployment
|
|
201
|
+
this.clusterTime = null;
|
|
202
|
+
|
|
203
|
+
// Add event listener
|
|
204
|
+
EventEmitter.call(this);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
inherits(Mongos, EventEmitter);
|
|
208
|
+
Object.assign(Mongos.prototype, SessionMixins);
|
|
209
|
+
|
|
210
|
+
Object.defineProperty(Mongos.prototype, 'type', {
|
|
211
|
+
enumerable: true,
|
|
212
|
+
get: function() {
|
|
213
|
+
return 'mongos';
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
Object.defineProperty(Mongos.prototype, 'parserType', {
|
|
218
|
+
enumerable: true,
|
|
219
|
+
get: function() {
|
|
220
|
+
return BSON.native ? 'c++' : 'js';
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
Object.defineProperty(Mongos.prototype, 'logicalSessionTimeoutMinutes', {
|
|
225
|
+
enumerable: true,
|
|
226
|
+
get: function() {
|
|
227
|
+
if (!this.ismaster) return null;
|
|
228
|
+
return this.ismaster.logicalSessionTimeoutMinutes || null;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Emit event if it exists
|
|
234
|
+
* @method
|
|
235
|
+
*/
|
|
236
|
+
function emitSDAMEvent(self, event, description) {
|
|
237
|
+
if (self.listeners(event).length > 0) {
|
|
238
|
+
self.emit(event, description);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const SERVER_EVENTS = ['serverDescriptionChanged', 'error', 'close', 'timeout', 'parseError'];
|
|
243
|
+
function destroyServer(server, options, callback) {
|
|
244
|
+
options = options || {};
|
|
245
|
+
SERVER_EVENTS.forEach(event => server.removeAllListeners(event));
|
|
246
|
+
server.destroy(options, callback);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Initiate server connect
|
|
251
|
+
*/
|
|
252
|
+
Mongos.prototype.connect = function(options) {
|
|
253
|
+
var self = this;
|
|
254
|
+
// Add any connect level options to the internal state
|
|
255
|
+
this.s.connectOptions = options || {};
|
|
256
|
+
|
|
257
|
+
// Set connecting state
|
|
258
|
+
stateTransition(this, CONNECTING);
|
|
259
|
+
|
|
260
|
+
// Create server instances
|
|
261
|
+
var servers = this.s.seedlist.map(function(x) {
|
|
262
|
+
const server = new Server(
|
|
263
|
+
Object.assign({}, self.s.options, x, options, {
|
|
264
|
+
reconnect: false,
|
|
265
|
+
monitoring: false,
|
|
266
|
+
parent: self,
|
|
267
|
+
clientInfo: clone(self.s.clientInfo)
|
|
268
|
+
})
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
relayEvents(server, self, ['serverDescriptionChanged']);
|
|
272
|
+
return server;
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Emit the topology opening event
|
|
276
|
+
emitSDAMEvent(this, 'topologyOpening', { topologyId: this.id });
|
|
277
|
+
|
|
278
|
+
// Start all server connections
|
|
279
|
+
connectProxies(self, servers);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Authenticate the topology.
|
|
284
|
+
* @method
|
|
285
|
+
* @param {MongoCredentials} credentials The credentials for authentication we are using
|
|
286
|
+
* @param {authResultCallback} callback A callback function
|
|
287
|
+
*/
|
|
288
|
+
Mongos.prototype.auth = function(credentials, callback) {
|
|
289
|
+
if (typeof callback === 'function') callback(null, null);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
function handleEvent(self) {
|
|
293
|
+
return function() {
|
|
294
|
+
if (self.state === DESTROYED) return;
|
|
295
|
+
// Move to list of disconnectedProxies
|
|
296
|
+
moveServerFrom(self.connectedProxies, self.disconnectedProxies, this);
|
|
297
|
+
// Emit the initial topology
|
|
298
|
+
emitTopologyDescriptionChanged(self);
|
|
299
|
+
// Emit the left signal
|
|
300
|
+
self.emit('left', 'mongos', this);
|
|
301
|
+
// Emit the sdam event
|
|
302
|
+
self.emit('serverClosed', {
|
|
303
|
+
topologyId: self.id,
|
|
304
|
+
address: this.name
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function handleInitialConnectEvent(self, event) {
|
|
310
|
+
return function() {
|
|
311
|
+
var _this = this;
|
|
312
|
+
|
|
313
|
+
// Destroy the instance
|
|
314
|
+
if (self.state === DESTROYED) {
|
|
315
|
+
// Emit the initial topology
|
|
316
|
+
emitTopologyDescriptionChanged(self);
|
|
317
|
+
// Move from connectingProxies
|
|
318
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, this);
|
|
319
|
+
return this.destroy();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Check the type of server
|
|
323
|
+
if (event === 'connect') {
|
|
324
|
+
// Get last known ismaster
|
|
325
|
+
self.ismaster = _this.lastIsMaster();
|
|
326
|
+
|
|
327
|
+
// Is this not a proxy, remove t
|
|
328
|
+
if (self.ismaster.msg === 'isdbgrid') {
|
|
329
|
+
// Add to the connectd list
|
|
330
|
+
for (let i = 0; i < self.connectedProxies.length; i++) {
|
|
331
|
+
if (self.connectedProxies[i].name === _this.name) {
|
|
332
|
+
// Move from connectingProxies
|
|
333
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _this);
|
|
334
|
+
// Emit the initial topology
|
|
335
|
+
emitTopologyDescriptionChanged(self);
|
|
336
|
+
_this.destroy();
|
|
337
|
+
return self.emit('failed', _this);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Remove the handlers
|
|
342
|
+
for (let i = 0; i < handlers.length; i++) {
|
|
343
|
+
_this.removeAllListeners(handlers[i]);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Add stable state handlers
|
|
347
|
+
_this.on('error', handleEvent(self, 'error'));
|
|
348
|
+
_this.on('close', handleEvent(self, 'close'));
|
|
349
|
+
_this.on('timeout', handleEvent(self, 'timeout'));
|
|
350
|
+
_this.on('parseError', handleEvent(self, 'parseError'));
|
|
351
|
+
|
|
352
|
+
// Move from connecting proxies connected
|
|
353
|
+
moveServerFrom(self.connectingProxies, self.connectedProxies, _this);
|
|
354
|
+
// Emit the joined event
|
|
355
|
+
self.emit('joined', 'mongos', _this);
|
|
356
|
+
} else {
|
|
357
|
+
// Print warning if we did not find a mongos proxy
|
|
358
|
+
if (self.s.logger.isWarn()) {
|
|
359
|
+
var message = 'expected mongos proxy, but found replicaset member mongod for server %s';
|
|
360
|
+
// We have a standalone server
|
|
361
|
+
if (!self.ismaster.hosts) {
|
|
362
|
+
message = 'expected mongos proxy, but found standalone mongod for server %s';
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
self.s.logger.warn(f(message, _this.name));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// This is not a mongos proxy, remove it completely
|
|
369
|
+
removeProxyFrom(self.connectingProxies, _this);
|
|
370
|
+
// Emit the left event
|
|
371
|
+
self.emit('left', 'server', _this);
|
|
372
|
+
// Emit failed event
|
|
373
|
+
self.emit('failed', _this);
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, this);
|
|
377
|
+
// Emit the left event
|
|
378
|
+
self.emit('left', 'mongos', this);
|
|
379
|
+
// Emit failed event
|
|
380
|
+
self.emit('failed', this);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Emit the initial topology
|
|
384
|
+
emitTopologyDescriptionChanged(self);
|
|
385
|
+
|
|
386
|
+
// Trigger topologyMonitor
|
|
387
|
+
if (self.connectingProxies.length === 0) {
|
|
388
|
+
// Emit connected if we are connected
|
|
389
|
+
if (self.connectedProxies.length > 0 && self.state === CONNECTING) {
|
|
390
|
+
// Set the state to connected
|
|
391
|
+
stateTransition(self, CONNECTED);
|
|
392
|
+
// Emit the connect event
|
|
393
|
+
self.emit('connect', self);
|
|
394
|
+
self.emit('fullsetup', self);
|
|
395
|
+
self.emit('all', self);
|
|
396
|
+
} else if (self.disconnectedProxies.length === 0) {
|
|
397
|
+
// Print warning if we did not find a mongos proxy
|
|
398
|
+
if (self.s.logger.isWarn()) {
|
|
399
|
+
self.s.logger.warn(
|
|
400
|
+
f('no mongos proxies found in seed list, did you mean to connect to a replicaset')
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Emit the error that no proxies were found
|
|
405
|
+
return self.emit('error', new MongoError('no mongos proxies found in seed list'));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Topology monitor
|
|
409
|
+
topologyMonitor(self, { firstConnect: true });
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function connectProxies(self, servers) {
|
|
415
|
+
// Update connectingProxies
|
|
416
|
+
self.connectingProxies = self.connectingProxies.concat(servers);
|
|
417
|
+
|
|
418
|
+
// Index used to interleaf the server connects, avoiding
|
|
419
|
+
// runtime issues on io constrained vm's
|
|
420
|
+
var timeoutInterval = 0;
|
|
421
|
+
|
|
422
|
+
function connect(server, timeoutInterval) {
|
|
423
|
+
setTimeout(function() {
|
|
424
|
+
// Emit opening server event
|
|
425
|
+
self.emit('serverOpening', {
|
|
426
|
+
topologyId: self.id,
|
|
427
|
+
address: server.name
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Emit the initial topology
|
|
431
|
+
emitTopologyDescriptionChanged(self);
|
|
432
|
+
|
|
433
|
+
// Add event handlers
|
|
434
|
+
server.once('close', handleInitialConnectEvent(self, 'close'));
|
|
435
|
+
server.once('timeout', handleInitialConnectEvent(self, 'timeout'));
|
|
436
|
+
server.once('parseError', handleInitialConnectEvent(self, 'parseError'));
|
|
437
|
+
server.once('error', handleInitialConnectEvent(self, 'error'));
|
|
438
|
+
server.once('connect', handleInitialConnectEvent(self, 'connect'));
|
|
439
|
+
|
|
440
|
+
// Command Monitoring events
|
|
441
|
+
relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
|
|
442
|
+
|
|
443
|
+
// Start connection
|
|
444
|
+
server.connect(self.s.connectOptions);
|
|
445
|
+
}, timeoutInterval);
|
|
446
|
+
}
|
|
447
|
+
// Start all the servers
|
|
448
|
+
while (servers.length > 0) {
|
|
449
|
+
connect(servers.shift(), timeoutInterval++);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function pickProxy(self, session) {
|
|
454
|
+
// TODO: Destructure :)
|
|
455
|
+
const transaction = session && session.transaction;
|
|
456
|
+
|
|
457
|
+
if (transaction && transaction.server) {
|
|
458
|
+
if (transaction.server.isConnected()) {
|
|
459
|
+
return transaction.server;
|
|
460
|
+
} else {
|
|
461
|
+
transaction.unpinServer();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Get the currently connected Proxies
|
|
466
|
+
var connectedProxies = self.connectedProxies.slice(0);
|
|
467
|
+
|
|
468
|
+
// Set lower bound
|
|
469
|
+
var lowerBoundLatency = Number.MAX_VALUE;
|
|
470
|
+
|
|
471
|
+
// Determine the lower bound for the Proxies
|
|
472
|
+
for (var i = 0; i < connectedProxies.length; i++) {
|
|
473
|
+
if (connectedProxies[i].lastIsMasterMS < lowerBoundLatency) {
|
|
474
|
+
lowerBoundLatency = connectedProxies[i].lastIsMasterMS;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Filter out the possible servers
|
|
479
|
+
connectedProxies = connectedProxies.filter(function(server) {
|
|
480
|
+
if (
|
|
481
|
+
server.lastIsMasterMS <= lowerBoundLatency + self.s.localThresholdMS &&
|
|
482
|
+
server.isConnected()
|
|
483
|
+
) {
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
let proxy;
|
|
489
|
+
|
|
490
|
+
// We have no connectedProxies pick first of the connected ones
|
|
491
|
+
if (connectedProxies.length === 0) {
|
|
492
|
+
proxy = self.connectedProxies[0];
|
|
493
|
+
} else {
|
|
494
|
+
// Get proxy
|
|
495
|
+
proxy = connectedProxies[self.index % connectedProxies.length];
|
|
496
|
+
// Update the index
|
|
497
|
+
self.index = (self.index + 1) % connectedProxies.length;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (transaction && transaction.isActive && proxy && proxy.isConnected()) {
|
|
501
|
+
transaction.pinServer(proxy);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Return the proxy
|
|
505
|
+
return proxy;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function moveServerFrom(from, to, proxy) {
|
|
509
|
+
for (var i = 0; i < from.length; i++) {
|
|
510
|
+
if (from[i].name === proxy.name) {
|
|
511
|
+
from.splice(i, 1);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
for (i = 0; i < to.length; i++) {
|
|
516
|
+
if (to[i].name === proxy.name) {
|
|
517
|
+
to.splice(i, 1);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
to.push(proxy);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function removeProxyFrom(from, proxy) {
|
|
525
|
+
for (var i = 0; i < from.length; i++) {
|
|
526
|
+
if (from[i].name === proxy.name) {
|
|
527
|
+
from.splice(i, 1);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function reconnectProxies(self, proxies, callback) {
|
|
533
|
+
// Count lefts
|
|
534
|
+
var count = proxies.length;
|
|
535
|
+
|
|
536
|
+
// Handle events
|
|
537
|
+
var _handleEvent = function(self, event) {
|
|
538
|
+
return function() {
|
|
539
|
+
var _self = this;
|
|
540
|
+
count = count - 1;
|
|
541
|
+
|
|
542
|
+
// Destroyed
|
|
543
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) {
|
|
544
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
|
|
545
|
+
return this.destroy();
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (event === 'connect') {
|
|
549
|
+
// Destroyed
|
|
550
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) {
|
|
551
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
|
|
552
|
+
return _self.destroy();
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Remove the handlers
|
|
556
|
+
for (var i = 0; i < handlers.length; i++) {
|
|
557
|
+
_self.removeAllListeners(handlers[i]);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// Add stable state handlers
|
|
561
|
+
_self.on('error', handleEvent(self, 'error'));
|
|
562
|
+
_self.on('close', handleEvent(self, 'close'));
|
|
563
|
+
_self.on('timeout', handleEvent(self, 'timeout'));
|
|
564
|
+
_self.on('parseError', handleEvent(self, 'parseError'));
|
|
565
|
+
|
|
566
|
+
// Move to the connected servers
|
|
567
|
+
moveServerFrom(self.connectingProxies, self.connectedProxies, _self);
|
|
568
|
+
// Emit topology Change
|
|
569
|
+
emitTopologyDescriptionChanged(self);
|
|
570
|
+
// Emit joined event
|
|
571
|
+
self.emit('joined', 'mongos', _self);
|
|
572
|
+
} else {
|
|
573
|
+
// Move from connectingProxies
|
|
574
|
+
moveServerFrom(self.connectingProxies, self.disconnectedProxies, _self);
|
|
575
|
+
this.destroy();
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// Are we done finish up callback
|
|
579
|
+
if (count === 0) {
|
|
580
|
+
callback();
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// No new servers
|
|
586
|
+
if (count === 0) {
|
|
587
|
+
return callback();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Execute method
|
|
591
|
+
function execute(_server, i) {
|
|
592
|
+
setTimeout(function() {
|
|
593
|
+
// Destroyed
|
|
594
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Create a new server instance
|
|
599
|
+
var server = new Server(
|
|
600
|
+
Object.assign({}, self.s.options, {
|
|
601
|
+
host: _server.name.split(':')[0],
|
|
602
|
+
port: parseInt(_server.name.split(':')[1], 10),
|
|
603
|
+
reconnect: false,
|
|
604
|
+
monitoring: false,
|
|
605
|
+
parent: self,
|
|
606
|
+
clientInfo: clone(self.s.clientInfo)
|
|
607
|
+
})
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
destroyServer(_server);
|
|
611
|
+
removeProxyFrom(self.disconnectedProxies, _server);
|
|
612
|
+
|
|
613
|
+
// Relay the server description change
|
|
614
|
+
relayEvents(server, self, ['serverDescriptionChanged']);
|
|
615
|
+
|
|
616
|
+
// Emit opening server event
|
|
617
|
+
self.emit('serverOpening', {
|
|
618
|
+
topologyId: server.s.topologyId !== -1 ? server.s.topologyId : self.id,
|
|
619
|
+
address: server.name
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
// Add temp handlers
|
|
623
|
+
server.once('connect', _handleEvent(self, 'connect'));
|
|
624
|
+
server.once('close', _handleEvent(self, 'close'));
|
|
625
|
+
server.once('timeout', _handleEvent(self, 'timeout'));
|
|
626
|
+
server.once('error', _handleEvent(self, 'error'));
|
|
627
|
+
server.once('parseError', _handleEvent(self, 'parseError'));
|
|
628
|
+
|
|
629
|
+
// Command Monitoring events
|
|
630
|
+
relayEvents(server, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
|
|
631
|
+
|
|
632
|
+
// Connect to proxy
|
|
633
|
+
self.connectingProxies.push(server);
|
|
634
|
+
server.connect(self.s.connectOptions);
|
|
635
|
+
}, i);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Create new instances
|
|
639
|
+
for (var i = 0; i < proxies.length; i++) {
|
|
640
|
+
execute(proxies[i], i);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function topologyMonitor(self, options) {
|
|
645
|
+
options = options || {};
|
|
646
|
+
|
|
647
|
+
// Set momitoring timeout
|
|
648
|
+
self.haTimeoutId = setTimeout(function() {
|
|
649
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) return;
|
|
650
|
+
// If we have a primary and a disconnect handler, execute
|
|
651
|
+
// buffered operations
|
|
652
|
+
if (self.isConnected() && self.s.disconnectHandler) {
|
|
653
|
+
self.s.disconnectHandler.execute();
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Get the connectingServers
|
|
657
|
+
var proxies = self.connectedProxies.slice(0);
|
|
658
|
+
// Get the count
|
|
659
|
+
var count = proxies.length;
|
|
660
|
+
|
|
661
|
+
// If the count is zero schedule a new fast
|
|
662
|
+
function pingServer(_self, _server, cb) {
|
|
663
|
+
// Measure running time
|
|
664
|
+
var start = new Date().getTime();
|
|
665
|
+
|
|
666
|
+
// Emit the server heartbeat start
|
|
667
|
+
emitSDAMEvent(self, 'serverHeartbeatStarted', { connectionId: _server.name });
|
|
668
|
+
|
|
669
|
+
// Execute ismaster
|
|
670
|
+
_server.command(
|
|
671
|
+
'admin.$cmd',
|
|
672
|
+
{
|
|
673
|
+
ismaster: true
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
monitoring: true,
|
|
677
|
+
socketTimeout: self.s.options.connectionTimeout || 2000
|
|
678
|
+
},
|
|
679
|
+
function(err, r) {
|
|
680
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) {
|
|
681
|
+
// Move from connectingProxies
|
|
682
|
+
moveServerFrom(self.connectedProxies, self.disconnectedProxies, _server);
|
|
683
|
+
_server.destroy();
|
|
684
|
+
return cb(err, r);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Calculate latency
|
|
688
|
+
var latencyMS = new Date().getTime() - start;
|
|
689
|
+
|
|
690
|
+
// We had an error, remove it from the state
|
|
691
|
+
if (err) {
|
|
692
|
+
// Emit the server heartbeat failure
|
|
693
|
+
emitSDAMEvent(self, 'serverHeartbeatFailed', {
|
|
694
|
+
durationMS: latencyMS,
|
|
695
|
+
failure: err,
|
|
696
|
+
connectionId: _server.name
|
|
697
|
+
});
|
|
698
|
+
// Move from connected proxies to disconnected proxies
|
|
699
|
+
moveServerFrom(self.connectedProxies, self.disconnectedProxies, _server);
|
|
700
|
+
} else {
|
|
701
|
+
// Update the server ismaster
|
|
702
|
+
_server.ismaster = r.result;
|
|
703
|
+
_server.lastIsMasterMS = latencyMS;
|
|
704
|
+
|
|
705
|
+
// Server heart beat event
|
|
706
|
+
emitSDAMEvent(self, 'serverHeartbeatSucceeded', {
|
|
707
|
+
durationMS: latencyMS,
|
|
708
|
+
reply: r.result,
|
|
709
|
+
connectionId: _server.name
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
cb(err, r);
|
|
714
|
+
}
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// No proxies initiate monitor again
|
|
719
|
+
if (proxies.length === 0) {
|
|
720
|
+
// Emit close event if any listeners registered
|
|
721
|
+
if (self.listeners('close').length > 0 && self.state === CONNECTING) {
|
|
722
|
+
self.emit('error', new MongoError('no mongos proxy available'));
|
|
723
|
+
} else {
|
|
724
|
+
self.emit('close', self);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Attempt to connect to any unknown servers
|
|
728
|
+
return reconnectProxies(self, self.disconnectedProxies, function() {
|
|
729
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) return;
|
|
730
|
+
|
|
731
|
+
// Are we connected ? emit connect event
|
|
732
|
+
if (self.state === CONNECTING && options.firstConnect) {
|
|
733
|
+
self.emit('connect', self);
|
|
734
|
+
self.emit('fullsetup', self);
|
|
735
|
+
self.emit('all', self);
|
|
736
|
+
} else if (self.isConnected()) {
|
|
737
|
+
self.emit('reconnect', self);
|
|
738
|
+
} else if (!self.isConnected() && self.listeners('close').length > 0) {
|
|
739
|
+
self.emit('close', self);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Perform topology monitor
|
|
743
|
+
topologyMonitor(self);
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// Ping all servers
|
|
748
|
+
for (var i = 0; i < proxies.length; i++) {
|
|
749
|
+
pingServer(self, proxies[i], function() {
|
|
750
|
+
count = count - 1;
|
|
751
|
+
|
|
752
|
+
if (count === 0) {
|
|
753
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) return;
|
|
754
|
+
|
|
755
|
+
// Attempt to connect to any unknown servers
|
|
756
|
+
reconnectProxies(self, self.disconnectedProxies, function() {
|
|
757
|
+
if (self.state === DESTROYED || self.state === UNREFERENCED) return;
|
|
758
|
+
// Perform topology monitor
|
|
759
|
+
topologyMonitor(self);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}, self.s.haInterval);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Returns the last known ismaster document for this server
|
|
769
|
+
* @method
|
|
770
|
+
* @return {object}
|
|
771
|
+
*/
|
|
772
|
+
Mongos.prototype.lastIsMaster = function() {
|
|
773
|
+
return this.ismaster;
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Unref all connections belong to this server
|
|
778
|
+
* @method
|
|
779
|
+
*/
|
|
780
|
+
Mongos.prototype.unref = function() {
|
|
781
|
+
// Transition state
|
|
782
|
+
stateTransition(this, UNREFERENCED);
|
|
783
|
+
// Get all proxies
|
|
784
|
+
var proxies = this.connectedProxies.concat(this.connectingProxies);
|
|
785
|
+
proxies.forEach(function(x) {
|
|
786
|
+
x.unref();
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
clearTimeout(this.haTimeoutId);
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Destroy the server connection
|
|
794
|
+
* @param {boolean} [options.force=false] Force destroy the pool
|
|
795
|
+
* @method
|
|
796
|
+
*/
|
|
797
|
+
Mongos.prototype.destroy = function(options, callback) {
|
|
798
|
+
if (this.haTimeoutId) {
|
|
799
|
+
clearTimeout(this.haTimeoutId);
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
const proxies = this.connectedProxies.concat(this.connectingProxies);
|
|
803
|
+
let serverCount = proxies.length;
|
|
804
|
+
const serverDestroyed = () => {
|
|
805
|
+
serverCount--;
|
|
806
|
+
if (serverCount > 0) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
emitTopologyDescriptionChanged(this);
|
|
811
|
+
emitSDAMEvent(this, 'topologyClosed', { topologyId: this.id });
|
|
812
|
+
stateTransition(this, DESTROYED);
|
|
813
|
+
if (typeof callback === 'function') {
|
|
814
|
+
callback(null, null);
|
|
815
|
+
}
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
if (serverCount === 0) {
|
|
819
|
+
serverDestroyed();
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Destroy all connecting servers
|
|
824
|
+
proxies.forEach(server => {
|
|
825
|
+
// Emit the sdam event
|
|
826
|
+
this.emit('serverClosed', {
|
|
827
|
+
topologyId: this.id,
|
|
828
|
+
address: server.name
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
destroyServer(server, options, serverDestroyed);
|
|
832
|
+
moveServerFrom(this.connectedProxies, this.disconnectedProxies, server);
|
|
833
|
+
});
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
/**
|
|
837
|
+
* Figure out if the server is connected
|
|
838
|
+
* @method
|
|
839
|
+
* @return {boolean}
|
|
840
|
+
*/
|
|
841
|
+
Mongos.prototype.isConnected = function() {
|
|
842
|
+
return this.connectedProxies.length > 0;
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Figure out if the server instance was destroyed by calling destroy
|
|
847
|
+
* @method
|
|
848
|
+
* @return {boolean}
|
|
849
|
+
*/
|
|
850
|
+
Mongos.prototype.isDestroyed = function() {
|
|
851
|
+
return this.state === DESTROYED;
|
|
852
|
+
};
|
|
853
|
+
|
|
854
|
+
//
|
|
855
|
+
// Operations
|
|
856
|
+
//
|
|
857
|
+
|
|
858
|
+
function executeWriteOperation(args, options, callback) {
|
|
859
|
+
if (typeof options === 'function') (callback = options), (options = {});
|
|
860
|
+
options = options || {};
|
|
861
|
+
|
|
862
|
+
// TODO: once we drop Node 4, use destructuring either here or in arguments.
|
|
863
|
+
const self = args.self;
|
|
864
|
+
const op = args.op;
|
|
865
|
+
const ns = args.ns;
|
|
866
|
+
const ops = args.ops;
|
|
867
|
+
|
|
868
|
+
// Pick a server
|
|
869
|
+
let server = pickProxy(self, options.session);
|
|
870
|
+
// No server found error out
|
|
871
|
+
if (!server) return callback(new MongoError('no mongos proxy available'));
|
|
872
|
+
|
|
873
|
+
const willRetryWrite =
|
|
874
|
+
!args.retrying &&
|
|
875
|
+
!!options.retryWrites &&
|
|
876
|
+
options.session &&
|
|
877
|
+
isRetryableWritesSupported(self) &&
|
|
878
|
+
!options.session.inTransaction();
|
|
879
|
+
|
|
880
|
+
const handler = (err, result) => {
|
|
881
|
+
if (!err) return callback(null, result);
|
|
882
|
+
if (!isRetryableError(err) || !willRetryWrite) {
|
|
883
|
+
return callback(err);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Pick another server
|
|
887
|
+
server = pickProxy(self, options.session);
|
|
888
|
+
|
|
889
|
+
// No server found error out with original error
|
|
890
|
+
if (!server) {
|
|
891
|
+
return callback(err);
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
const newArgs = Object.assign({}, args, { retrying: true });
|
|
895
|
+
return executeWriteOperation(newArgs, options, callback);
|
|
896
|
+
};
|
|
897
|
+
|
|
898
|
+
if (callback.operationId) {
|
|
899
|
+
handler.operationId = callback.operationId;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// increment and assign txnNumber
|
|
903
|
+
if (willRetryWrite) {
|
|
904
|
+
options.session.incrementTransactionNumber();
|
|
905
|
+
options.willRetryWrite = willRetryWrite;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// rerun the operation
|
|
909
|
+
server[op](ns, ops, options, handler);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/**
|
|
913
|
+
* Insert one or more documents
|
|
914
|
+
* @method
|
|
915
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
916
|
+
* @param {array} ops An array of documents to insert
|
|
917
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
918
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
919
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
920
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
921
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
922
|
+
* @param {boolean} [options.retryWrites] Enable retryable writes for this operation
|
|
923
|
+
* @param {opResultCallback} callback A callback function
|
|
924
|
+
*/
|
|
925
|
+
Mongos.prototype.insert = function(ns, ops, options, callback) {
|
|
926
|
+
if (typeof options === 'function') {
|
|
927
|
+
(callback = options), (options = {}), (options = options || {});
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
if (this.state === DESTROYED) return callback(new MongoError(f('topology was destroyed')));
|
|
931
|
+
|
|
932
|
+
// Not connected but we have a disconnecthandler
|
|
933
|
+
if (!this.isConnected() && this.s.disconnectHandler != null) {
|
|
934
|
+
return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// No mongos proxy available
|
|
938
|
+
if (!this.isConnected()) {
|
|
939
|
+
return callback(new MongoError('no mongos proxy available'));
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// Execute write operation
|
|
943
|
+
executeWriteOperation({ self: this, op: 'insert', ns, ops }, options, callback);
|
|
944
|
+
};
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Perform one or more update operations
|
|
948
|
+
* @method
|
|
949
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
950
|
+
* @param {array} ops An array of updates
|
|
951
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
952
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
953
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
954
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
955
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
956
|
+
* @param {boolean} [options.retryWrites] Enable retryable writes for this operation
|
|
957
|
+
* @param {opResultCallback} callback A callback function
|
|
958
|
+
*/
|
|
959
|
+
Mongos.prototype.update = function(ns, ops, options, callback) {
|
|
960
|
+
if (typeof options === 'function') {
|
|
961
|
+
(callback = options), (options = {}), (options = options || {});
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
if (this.state === DESTROYED) return callback(new MongoError(f('topology was destroyed')));
|
|
965
|
+
|
|
966
|
+
// Not connected but we have a disconnecthandler
|
|
967
|
+
if (!this.isConnected() && this.s.disconnectHandler != null) {
|
|
968
|
+
return this.s.disconnectHandler.add('update', ns, ops, options, callback);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// No mongos proxy available
|
|
972
|
+
if (!this.isConnected()) {
|
|
973
|
+
return callback(new MongoError('no mongos proxy available'));
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// Execute write operation
|
|
977
|
+
executeWriteOperation({ self: this, op: 'update', ns, ops }, options, callback);
|
|
978
|
+
};
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Perform one or more remove operations
|
|
982
|
+
* @method
|
|
983
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
984
|
+
* @param {array} ops An array of removes
|
|
985
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
986
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
987
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
988
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
989
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
990
|
+
* @param {boolean} [options.retryWrites] Enable retryable writes for this operation
|
|
991
|
+
* @param {opResultCallback} callback A callback function
|
|
992
|
+
*/
|
|
993
|
+
Mongos.prototype.remove = function(ns, ops, options, callback) {
|
|
994
|
+
if (typeof options === 'function') {
|
|
995
|
+
(callback = options), (options = {}), (options = options || {});
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (this.state === DESTROYED) return callback(new MongoError(f('topology was destroyed')));
|
|
999
|
+
|
|
1000
|
+
// Not connected but we have a disconnecthandler
|
|
1001
|
+
if (!this.isConnected() && this.s.disconnectHandler != null) {
|
|
1002
|
+
return this.s.disconnectHandler.add('remove', ns, ops, options, callback);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// No mongos proxy available
|
|
1006
|
+
if (!this.isConnected()) {
|
|
1007
|
+
return callback(new MongoError('no mongos proxy available'));
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// Execute write operation
|
|
1011
|
+
executeWriteOperation({ self: this, op: 'remove', ns, ops }, options, callback);
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
const RETRYABLE_WRITE_OPERATIONS = ['findAndModify', 'insert', 'update', 'delete'];
|
|
1015
|
+
|
|
1016
|
+
function isWriteCommand(command) {
|
|
1017
|
+
return RETRYABLE_WRITE_OPERATIONS.some(op => command[op]);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Execute a command
|
|
1022
|
+
* @method
|
|
1023
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
1024
|
+
* @param {object} cmd The command hash
|
|
1025
|
+
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
|
|
1026
|
+
* @param {Connection} [options.connection] Specify connection object to execute command against
|
|
1027
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
1028
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
1029
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
1030
|
+
* @param {opResultCallback} callback A callback function
|
|
1031
|
+
*/
|
|
1032
|
+
Mongos.prototype.command = function(ns, cmd, options, callback) {
|
|
1033
|
+
if (typeof options === 'function') {
|
|
1034
|
+
(callback = options), (options = {}), (options = options || {});
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
if (this.state === DESTROYED) return callback(new MongoError(f('topology was destroyed')));
|
|
1038
|
+
var self = this;
|
|
1039
|
+
|
|
1040
|
+
// Pick a proxy
|
|
1041
|
+
var server = pickProxy(self, options.session);
|
|
1042
|
+
|
|
1043
|
+
// Topology is not connected, save the call in the provided store to be
|
|
1044
|
+
// Executed at some point when the handler deems it's reconnected
|
|
1045
|
+
if ((server == null || !server.isConnected()) && this.s.disconnectHandler != null) {
|
|
1046
|
+
return this.s.disconnectHandler.add('command', ns, cmd, options, callback);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// No server returned we had an error
|
|
1050
|
+
if (server == null) {
|
|
1051
|
+
return callback(new MongoError('no mongos proxy available'));
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Cloned options
|
|
1055
|
+
var clonedOptions = cloneOptions(options);
|
|
1056
|
+
clonedOptions.topology = self;
|
|
1057
|
+
|
|
1058
|
+
const willRetryWrite =
|
|
1059
|
+
!options.retrying &&
|
|
1060
|
+
options.retryWrites &&
|
|
1061
|
+
options.session &&
|
|
1062
|
+
isRetryableWritesSupported(self) &&
|
|
1063
|
+
!options.session.inTransaction() &&
|
|
1064
|
+
isWriteCommand(cmd);
|
|
1065
|
+
|
|
1066
|
+
const cb = (err, result) => {
|
|
1067
|
+
if (!err) return callback(null, result);
|
|
1068
|
+
if (!isRetryableError(err)) {
|
|
1069
|
+
return callback(err);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
if (willRetryWrite) {
|
|
1073
|
+
const newOptions = Object.assign({}, clonedOptions, { retrying: true });
|
|
1074
|
+
return this.command(ns, cmd, newOptions, callback);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return callback(err);
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
// increment and assign txnNumber
|
|
1081
|
+
if (willRetryWrite) {
|
|
1082
|
+
options.session.incrementTransactionNumber();
|
|
1083
|
+
options.willRetryWrite = willRetryWrite;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Execute the command
|
|
1087
|
+
server.command(ns, cmd, clonedOptions, cb);
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Get a new cursor
|
|
1092
|
+
* @method
|
|
1093
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
1094
|
+
* @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
|
|
1095
|
+
* @param {object} [options] Options for the cursor
|
|
1096
|
+
* @param {object} [options.batchSize=0] Batchsize for the operation
|
|
1097
|
+
* @param {array} [options.documents=[]] Initial documents list for cursor
|
|
1098
|
+
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
|
|
1099
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
1100
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
1101
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
1102
|
+
* @param {object} [options.topology] The internal topology of the created cursor
|
|
1103
|
+
* @returns {Cursor}
|
|
1104
|
+
*/
|
|
1105
|
+
Mongos.prototype.cursor = function(ns, cmd, options) {
|
|
1106
|
+
options = options || {};
|
|
1107
|
+
const topology = options.topology || this;
|
|
1108
|
+
|
|
1109
|
+
// Set up final cursor type
|
|
1110
|
+
var FinalCursor = options.cursorFactory || this.s.Cursor;
|
|
1111
|
+
|
|
1112
|
+
// Return the cursor
|
|
1113
|
+
return new FinalCursor(topology, ns, cmd, options);
|
|
1114
|
+
};
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Selects a server
|
|
1118
|
+
*
|
|
1119
|
+
* @method
|
|
1120
|
+
* @param {function} selector Unused
|
|
1121
|
+
* @param {ReadPreference} [options.readPreference] Unused
|
|
1122
|
+
* @param {ClientSession} [options.session] Specify a session if it is being used
|
|
1123
|
+
* @param {function} callback
|
|
1124
|
+
*/
|
|
1125
|
+
Mongos.prototype.selectServer = function(selector, options, callback) {
|
|
1126
|
+
if (typeof selector === 'function' && typeof callback === 'undefined')
|
|
1127
|
+
(callback = selector), (selector = undefined), (options = {});
|
|
1128
|
+
if (typeof options === 'function')
|
|
1129
|
+
(callback = options), (options = selector), (selector = undefined);
|
|
1130
|
+
options = options || {};
|
|
1131
|
+
|
|
1132
|
+
const server = pickProxy(this, options.session);
|
|
1133
|
+
if (this.s.debug) this.emit('pickedServer', null, server);
|
|
1134
|
+
callback(null, server);
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* All raw connections
|
|
1139
|
+
* @method
|
|
1140
|
+
* @return {Connection[]}
|
|
1141
|
+
*/
|
|
1142
|
+
Mongos.prototype.connections = function() {
|
|
1143
|
+
var connections = [];
|
|
1144
|
+
|
|
1145
|
+
for (var i = 0; i < this.connectedProxies.length; i++) {
|
|
1146
|
+
connections = connections.concat(this.connectedProxies[i].connections());
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
return connections;
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
function emitTopologyDescriptionChanged(self) {
|
|
1153
|
+
if (self.listeners('topologyDescriptionChanged').length > 0) {
|
|
1154
|
+
var topology = 'Unknown';
|
|
1155
|
+
if (self.connectedProxies.length > 0) {
|
|
1156
|
+
topology = 'Sharded';
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
// Generate description
|
|
1160
|
+
var description = {
|
|
1161
|
+
topologyType: topology,
|
|
1162
|
+
servers: []
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
// All proxies
|
|
1166
|
+
var proxies = self.disconnectedProxies.concat(self.connectingProxies);
|
|
1167
|
+
|
|
1168
|
+
// Add all the disconnected proxies
|
|
1169
|
+
description.servers = description.servers.concat(
|
|
1170
|
+
proxies.map(function(x) {
|
|
1171
|
+
var description = x.getDescription();
|
|
1172
|
+
description.type = 'Unknown';
|
|
1173
|
+
return description;
|
|
1174
|
+
})
|
|
1175
|
+
);
|
|
1176
|
+
|
|
1177
|
+
// Add all the connected proxies
|
|
1178
|
+
description.servers = description.servers.concat(
|
|
1179
|
+
self.connectedProxies.map(function(x) {
|
|
1180
|
+
var description = x.getDescription();
|
|
1181
|
+
description.type = 'Mongos';
|
|
1182
|
+
return description;
|
|
1183
|
+
})
|
|
1184
|
+
);
|
|
1185
|
+
|
|
1186
|
+
// Get the diff
|
|
1187
|
+
var diffResult = diff(self.topologyDescription, description);
|
|
1188
|
+
|
|
1189
|
+
// Create the result
|
|
1190
|
+
var result = {
|
|
1191
|
+
topologyId: self.id,
|
|
1192
|
+
previousDescription: self.topologyDescription,
|
|
1193
|
+
newDescription: description,
|
|
1194
|
+
diff: diffResult
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
// Emit the topologyDescription change
|
|
1198
|
+
if (diffResult.servers.length > 0) {
|
|
1199
|
+
self.emit('topologyDescriptionChanged', result);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// Set the new description
|
|
1203
|
+
self.topologyDescription = description;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* A mongos connect event, used to verify that the connection is up and running
|
|
1209
|
+
*
|
|
1210
|
+
* @event Mongos#connect
|
|
1211
|
+
* @type {Mongos}
|
|
1212
|
+
*/
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* A mongos reconnect event, used to verify that the mongos topology has reconnected
|
|
1216
|
+
*
|
|
1217
|
+
* @event Mongos#reconnect
|
|
1218
|
+
* @type {Mongos}
|
|
1219
|
+
*/
|
|
1220
|
+
|
|
1221
|
+
/**
|
|
1222
|
+
* A mongos fullsetup event, used to signal that all topology members have been contacted.
|
|
1223
|
+
*
|
|
1224
|
+
* @event Mongos#fullsetup
|
|
1225
|
+
* @type {Mongos}
|
|
1226
|
+
*/
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* A mongos all event, used to signal that all topology members have been contacted.
|
|
1230
|
+
*
|
|
1231
|
+
* @event Mongos#all
|
|
1232
|
+
* @type {Mongos}
|
|
1233
|
+
*/
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* A server member left the mongos list
|
|
1237
|
+
*
|
|
1238
|
+
* @event Mongos#left
|
|
1239
|
+
* @type {Mongos}
|
|
1240
|
+
* @param {string} type The type of member that left (mongos)
|
|
1241
|
+
* @param {Server} server The server object that left
|
|
1242
|
+
*/
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* A server member joined the mongos list
|
|
1246
|
+
*
|
|
1247
|
+
* @event Mongos#joined
|
|
1248
|
+
* @type {Mongos}
|
|
1249
|
+
* @param {string} type The type of member that left (mongos)
|
|
1250
|
+
* @param {Server} server The server object that joined
|
|
1251
|
+
*/
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* A server opening SDAM monitoring event
|
|
1255
|
+
*
|
|
1256
|
+
* @event Mongos#serverOpening
|
|
1257
|
+
* @type {object}
|
|
1258
|
+
*/
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* A server closed SDAM monitoring event
|
|
1262
|
+
*
|
|
1263
|
+
* @event Mongos#serverClosed
|
|
1264
|
+
* @type {object}
|
|
1265
|
+
*/
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* A server description SDAM change monitoring event
|
|
1269
|
+
*
|
|
1270
|
+
* @event Mongos#serverDescriptionChanged
|
|
1271
|
+
* @type {object}
|
|
1272
|
+
*/
|
|
1273
|
+
|
|
1274
|
+
/**
|
|
1275
|
+
* A topology open SDAM event
|
|
1276
|
+
*
|
|
1277
|
+
* @event Mongos#topologyOpening
|
|
1278
|
+
* @type {object}
|
|
1279
|
+
*/
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* A topology closed SDAM event
|
|
1283
|
+
*
|
|
1284
|
+
* @event Mongos#topologyClosed
|
|
1285
|
+
* @type {object}
|
|
1286
|
+
*/
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* A topology structure SDAM change event
|
|
1290
|
+
*
|
|
1291
|
+
* @event Mongos#topologyDescriptionChanged
|
|
1292
|
+
* @type {object}
|
|
1293
|
+
*/
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* A topology serverHeartbeatStarted SDAM event
|
|
1297
|
+
*
|
|
1298
|
+
* @event Mongos#serverHeartbeatStarted
|
|
1299
|
+
* @type {object}
|
|
1300
|
+
*/
|
|
1301
|
+
|
|
1302
|
+
/**
|
|
1303
|
+
* A topology serverHeartbeatFailed SDAM event
|
|
1304
|
+
*
|
|
1305
|
+
* @event Mongos#serverHeartbeatFailed
|
|
1306
|
+
* @type {object}
|
|
1307
|
+
*/
|
|
1308
|
+
|
|
1309
|
+
/**
|
|
1310
|
+
* A topology serverHeartbeatSucceeded SDAM change event
|
|
1311
|
+
*
|
|
1312
|
+
* @event Mongos#serverHeartbeatSucceeded
|
|
1313
|
+
* @type {object}
|
|
1314
|
+
*/
|
|
1315
|
+
|
|
1316
|
+
/**
|
|
1317
|
+
* An event emitted indicating a command was started, if command monitoring is enabled
|
|
1318
|
+
*
|
|
1319
|
+
* @event Mongos#commandStarted
|
|
1320
|
+
* @type {object}
|
|
1321
|
+
*/
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* An event emitted indicating a command succeeded, if command monitoring is enabled
|
|
1325
|
+
*
|
|
1326
|
+
* @event Mongos#commandSucceeded
|
|
1327
|
+
* @type {object}
|
|
1328
|
+
*/
|
|
1329
|
+
|
|
1330
|
+
/**
|
|
1331
|
+
* An event emitted indicating a command failed, if command monitoring is enabled
|
|
1332
|
+
*
|
|
1333
|
+
* @event Mongos#commandFailed
|
|
1334
|
+
* @type {object}
|
|
1335
|
+
*/
|
|
1336
|
+
|
|
1337
|
+
module.exports = Mongos;
|