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,984 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var inherits = require('util').inherits,
|
|
4
|
+
f = require('util').format,
|
|
5
|
+
EventEmitter = require('events').EventEmitter,
|
|
6
|
+
ReadPreference = require('./read_preference'),
|
|
7
|
+
Logger = require('../connection/logger'),
|
|
8
|
+
debugOptions = require('../connection/utils').debugOptions,
|
|
9
|
+
retrieveBSON = require('../connection/utils').retrieveBSON,
|
|
10
|
+
Pool = require('../connection/pool'),
|
|
11
|
+
MongoError = require('../error').MongoError,
|
|
12
|
+
MongoNetworkError = require('../error').MongoNetworkError,
|
|
13
|
+
wireProtocol = require('../wireprotocol'),
|
|
14
|
+
BasicCursor = require('../cursor'),
|
|
15
|
+
sdam = require('./shared'),
|
|
16
|
+
createClientInfo = require('./shared').createClientInfo,
|
|
17
|
+
createCompressionInfo = require('./shared').createCompressionInfo,
|
|
18
|
+
resolveClusterTime = require('./shared').resolveClusterTime,
|
|
19
|
+
SessionMixins = require('./shared').SessionMixins,
|
|
20
|
+
relayEvents = require('../utils').relayEvents;
|
|
21
|
+
|
|
22
|
+
const collationNotSupported = require('../utils').collationNotSupported;
|
|
23
|
+
|
|
24
|
+
// Used for filtering out fields for loggin
|
|
25
|
+
var debugFields = [
|
|
26
|
+
'reconnect',
|
|
27
|
+
'reconnectTries',
|
|
28
|
+
'reconnectInterval',
|
|
29
|
+
'emitError',
|
|
30
|
+
'cursorFactory',
|
|
31
|
+
'host',
|
|
32
|
+
'port',
|
|
33
|
+
'size',
|
|
34
|
+
'keepAlive',
|
|
35
|
+
'keepAliveInitialDelay',
|
|
36
|
+
'noDelay',
|
|
37
|
+
'connectionTimeout',
|
|
38
|
+
'checkServerIdentity',
|
|
39
|
+
'socketTimeout',
|
|
40
|
+
'ssl',
|
|
41
|
+
'ca',
|
|
42
|
+
'crl',
|
|
43
|
+
'cert',
|
|
44
|
+
'key',
|
|
45
|
+
'rejectUnauthorized',
|
|
46
|
+
'promoteLongs',
|
|
47
|
+
'promoteValues',
|
|
48
|
+
'promoteBuffers',
|
|
49
|
+
'servername'
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Server instance id
|
|
53
|
+
var id = 0;
|
|
54
|
+
var serverAccounting = false;
|
|
55
|
+
var servers = {};
|
|
56
|
+
var BSON = retrieveBSON();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a new Server instance
|
|
60
|
+
* @class
|
|
61
|
+
* @param {boolean} [options.reconnect=true] Server will attempt to reconnect on loss of connection
|
|
62
|
+
* @param {number} [options.reconnectTries=30] Server attempt to reconnect #times
|
|
63
|
+
* @param {number} [options.reconnectInterval=1000] Server will wait # milliseconds between retries
|
|
64
|
+
* @param {number} [options.monitoring=true] Enable the server state monitoring (calling ismaster at monitoringInterval)
|
|
65
|
+
* @param {number} [options.monitoringInterval=5000] The interval of calling ismaster when monitoring is enabled.
|
|
66
|
+
* @param {Cursor} [options.cursorFactory=Cursor] The cursor factory class used for all query cursors
|
|
67
|
+
* @param {string} options.host The server host
|
|
68
|
+
* @param {number} options.port The server port
|
|
69
|
+
* @param {number} [options.size=5] Server connection pool size
|
|
70
|
+
* @param {boolean} [options.keepAlive=true] TCP Connection keep alive enabled
|
|
71
|
+
* @param {number} [options.keepAliveInitialDelay=300000] Initial delay before TCP keep alive enabled
|
|
72
|
+
* @param {boolean} [options.noDelay=true] TCP Connection no delay
|
|
73
|
+
* @param {number} [options.connectionTimeout=30000] TCP Connection timeout setting
|
|
74
|
+
* @param {number} [options.socketTimeout=360000] TCP Socket timeout setting
|
|
75
|
+
* @param {boolean} [options.ssl=false] Use SSL for connection
|
|
76
|
+
* @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.
|
|
77
|
+
* @param {Buffer} [options.ca] SSL Certificate store binary buffer
|
|
78
|
+
* @param {Buffer} [options.crl] SSL Certificate revocation store binary buffer
|
|
79
|
+
* @param {Buffer} [options.cert] SSL Certificate binary buffer
|
|
80
|
+
* @param {Buffer} [options.key] SSL Key file binary buffer
|
|
81
|
+
* @param {string} [options.passphrase] SSL Certificate pass phrase
|
|
82
|
+
* @param {boolean} [options.rejectUnauthorized=true] Reject unauthorized server certificates
|
|
83
|
+
* @param {string} [options.servername=null] String containing the server name requested via TLS SNI.
|
|
84
|
+
* @param {boolean} [options.promoteLongs=true] Convert Long values from the db into Numbers if they fit into 53 bits
|
|
85
|
+
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
86
|
+
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
87
|
+
* @param {string} [options.appname=null] Application name, passed in on ismaster call and logged in mongod server logs. Maximum size 128 bytes.
|
|
88
|
+
* @param {boolean} [options.domainsEnabled=false] Enable the wrapping of the callback in the current domain, disabled by default to avoid perf hit.
|
|
89
|
+
* @param {boolean} [options.monitorCommands=false] Enable command monitoring for this topology
|
|
90
|
+
* @return {Server} A cursor instance
|
|
91
|
+
* @fires Server#connect
|
|
92
|
+
* @fires Server#close
|
|
93
|
+
* @fires Server#error
|
|
94
|
+
* @fires Server#timeout
|
|
95
|
+
* @fires Server#parseError
|
|
96
|
+
* @fires Server#reconnect
|
|
97
|
+
* @fires Server#reconnectFailed
|
|
98
|
+
* @fires Server#serverHeartbeatStarted
|
|
99
|
+
* @fires Server#serverHeartbeatSucceeded
|
|
100
|
+
* @fires Server#serverHeartbeatFailed
|
|
101
|
+
* @fires Server#topologyOpening
|
|
102
|
+
* @fires Server#topologyClosed
|
|
103
|
+
* @fires Server#topologyDescriptionChanged
|
|
104
|
+
* @property {string} type the topology type.
|
|
105
|
+
* @property {string} parserType the parser type used (c++ or js).
|
|
106
|
+
*/
|
|
107
|
+
var Server = function(options) {
|
|
108
|
+
options = options || {};
|
|
109
|
+
|
|
110
|
+
// Add event listener
|
|
111
|
+
EventEmitter.call(this);
|
|
112
|
+
|
|
113
|
+
// Server instance id
|
|
114
|
+
this.id = id++;
|
|
115
|
+
|
|
116
|
+
// Internal state
|
|
117
|
+
this.s = {
|
|
118
|
+
// Options
|
|
119
|
+
options: options,
|
|
120
|
+
// Logger
|
|
121
|
+
logger: Logger('Server', options),
|
|
122
|
+
// Factory overrides
|
|
123
|
+
Cursor: options.cursorFactory || BasicCursor,
|
|
124
|
+
// BSON instance
|
|
125
|
+
bson:
|
|
126
|
+
options.bson ||
|
|
127
|
+
new BSON([
|
|
128
|
+
BSON.Binary,
|
|
129
|
+
BSON.Code,
|
|
130
|
+
BSON.DBRef,
|
|
131
|
+
BSON.Decimal128,
|
|
132
|
+
BSON.Double,
|
|
133
|
+
BSON.Int32,
|
|
134
|
+
BSON.Long,
|
|
135
|
+
BSON.Map,
|
|
136
|
+
BSON.MaxKey,
|
|
137
|
+
BSON.MinKey,
|
|
138
|
+
BSON.ObjectId,
|
|
139
|
+
BSON.BSONRegExp,
|
|
140
|
+
BSON.Symbol,
|
|
141
|
+
BSON.Timestamp
|
|
142
|
+
]),
|
|
143
|
+
// Pool
|
|
144
|
+
pool: null,
|
|
145
|
+
// Disconnect handler
|
|
146
|
+
disconnectHandler: options.disconnectHandler,
|
|
147
|
+
// Monitor thread (keeps the connection alive)
|
|
148
|
+
monitoring: typeof options.monitoring === 'boolean' ? options.monitoring : true,
|
|
149
|
+
// Is the server in a topology
|
|
150
|
+
inTopology: !!options.parent,
|
|
151
|
+
// Monitoring timeout
|
|
152
|
+
monitoringInterval:
|
|
153
|
+
typeof options.monitoringInterval === 'number' ? options.monitoringInterval : 5000,
|
|
154
|
+
// Topology id
|
|
155
|
+
topologyId: -1,
|
|
156
|
+
compression: { compressors: createCompressionInfo(options) },
|
|
157
|
+
// Optional parent topology
|
|
158
|
+
parent: options.parent
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// If this is a single deployment we need to track the clusterTime here
|
|
162
|
+
if (!this.s.parent) {
|
|
163
|
+
this.s.clusterTime = null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Curent ismaster
|
|
167
|
+
this.ismaster = null;
|
|
168
|
+
// Current ping time
|
|
169
|
+
this.lastIsMasterMS = -1;
|
|
170
|
+
// The monitoringProcessId
|
|
171
|
+
this.monitoringProcessId = null;
|
|
172
|
+
// Initial connection
|
|
173
|
+
this.initialConnect = true;
|
|
174
|
+
// Default type
|
|
175
|
+
this._type = 'server';
|
|
176
|
+
// Set the client info
|
|
177
|
+
this.clientInfo = createClientInfo(options);
|
|
178
|
+
|
|
179
|
+
// Max Stalleness values
|
|
180
|
+
// last time we updated the ismaster state
|
|
181
|
+
this.lastUpdateTime = 0;
|
|
182
|
+
// Last write time
|
|
183
|
+
this.lastWriteDate = 0;
|
|
184
|
+
// Stalleness
|
|
185
|
+
this.staleness = 0;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
inherits(Server, EventEmitter);
|
|
189
|
+
Object.assign(Server.prototype, SessionMixins);
|
|
190
|
+
|
|
191
|
+
Object.defineProperty(Server.prototype, 'type', {
|
|
192
|
+
enumerable: true,
|
|
193
|
+
get: function() {
|
|
194
|
+
return this._type;
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
Object.defineProperty(Server.prototype, 'parserType', {
|
|
199
|
+
enumerable: true,
|
|
200
|
+
get: function() {
|
|
201
|
+
return BSON.native ? 'c++' : 'js';
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
Object.defineProperty(Server.prototype, 'logicalSessionTimeoutMinutes', {
|
|
206
|
+
enumerable: true,
|
|
207
|
+
get: function() {
|
|
208
|
+
if (!this.ismaster) return null;
|
|
209
|
+
return this.ismaster.logicalSessionTimeoutMinutes || null;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// In single server deployments we track the clusterTime directly on the topology, however
|
|
214
|
+
// in Mongos and ReplSet deployments we instead need to delegate the clusterTime up to the
|
|
215
|
+
// tracking objects so we can ensure we are gossiping the maximum time received from the
|
|
216
|
+
// server.
|
|
217
|
+
Object.defineProperty(Server.prototype, 'clusterTime', {
|
|
218
|
+
enumerable: true,
|
|
219
|
+
set: function(clusterTime) {
|
|
220
|
+
const settings = this.s.parent ? this.s.parent : this.s;
|
|
221
|
+
resolveClusterTime(settings, clusterTime);
|
|
222
|
+
},
|
|
223
|
+
get: function() {
|
|
224
|
+
const settings = this.s.parent ? this.s.parent : this.s;
|
|
225
|
+
return settings.clusterTime || null;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
Server.enableServerAccounting = function() {
|
|
230
|
+
serverAccounting = true;
|
|
231
|
+
servers = {};
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
Server.disableServerAccounting = function() {
|
|
235
|
+
serverAccounting = false;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
Server.servers = function() {
|
|
239
|
+
return servers;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
Object.defineProperty(Server.prototype, 'name', {
|
|
243
|
+
enumerable: true,
|
|
244
|
+
get: function() {
|
|
245
|
+
return this.s.options.host + ':' + this.s.options.port;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
function disconnectHandler(self, type, ns, cmd, options, callback) {
|
|
250
|
+
// Topology is not connected, save the call in the provided store to be
|
|
251
|
+
// Executed at some point when the handler deems it's reconnected
|
|
252
|
+
if (
|
|
253
|
+
!self.s.pool.isConnected() &&
|
|
254
|
+
self.s.options.reconnect &&
|
|
255
|
+
self.s.disconnectHandler != null &&
|
|
256
|
+
!options.monitoring
|
|
257
|
+
) {
|
|
258
|
+
self.s.disconnectHandler.add(type, ns, cmd, options, callback);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// If we have no connection error
|
|
263
|
+
if (!self.s.pool.isConnected()) {
|
|
264
|
+
callback(new MongoError(f('no connection available to server %s', self.name)));
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function monitoringProcess(self) {
|
|
270
|
+
return function() {
|
|
271
|
+
// Pool was destroyed do not continue process
|
|
272
|
+
if (self.s.pool.isDestroyed()) return;
|
|
273
|
+
// Emit monitoring Process event
|
|
274
|
+
self.emit('monitoring', self);
|
|
275
|
+
// Perform ismaster call
|
|
276
|
+
// Get start time
|
|
277
|
+
var start = new Date().getTime();
|
|
278
|
+
|
|
279
|
+
// Execute the ismaster query
|
|
280
|
+
self.command(
|
|
281
|
+
'admin.$cmd',
|
|
282
|
+
{ ismaster: true },
|
|
283
|
+
{
|
|
284
|
+
socketTimeout:
|
|
285
|
+
typeof self.s.options.connectionTimeout !== 'number'
|
|
286
|
+
? 2000
|
|
287
|
+
: self.s.options.connectionTimeout,
|
|
288
|
+
monitoring: true
|
|
289
|
+
},
|
|
290
|
+
(err, result) => {
|
|
291
|
+
// Set initial lastIsMasterMS
|
|
292
|
+
self.lastIsMasterMS = new Date().getTime() - start;
|
|
293
|
+
if (self.s.pool.isDestroyed()) return;
|
|
294
|
+
// Update the ismaster view if we have a result
|
|
295
|
+
if (result) {
|
|
296
|
+
self.ismaster = result.result;
|
|
297
|
+
}
|
|
298
|
+
// Re-schedule the monitoring process
|
|
299
|
+
self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
var eventHandler = function(self, event) {
|
|
306
|
+
return function(err, conn) {
|
|
307
|
+
// Log information of received information if in info mode
|
|
308
|
+
if (self.s.logger.isInfo()) {
|
|
309
|
+
var object = err instanceof MongoError ? JSON.stringify(err) : {};
|
|
310
|
+
self.s.logger.info(
|
|
311
|
+
f('server %s fired event %s out with message %s', self.name, event, object)
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Handle connect event
|
|
316
|
+
if (event === 'connect') {
|
|
317
|
+
self.initialConnect = false;
|
|
318
|
+
self.ismaster = conn.ismaster;
|
|
319
|
+
self.lastIsMasterMS = conn.lastIsMasterMS;
|
|
320
|
+
if (conn.agreedCompressor) {
|
|
321
|
+
self.s.pool.options.agreedCompressor = conn.agreedCompressor;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (conn.zlibCompressionLevel) {
|
|
325
|
+
self.s.pool.options.zlibCompressionLevel = conn.zlibCompressionLevel;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (conn.ismaster.$clusterTime) {
|
|
329
|
+
const $clusterTime = conn.ismaster.$clusterTime;
|
|
330
|
+
self.clusterTime = $clusterTime;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// It's a proxy change the type so
|
|
334
|
+
// the wireprotocol will send $readPreference
|
|
335
|
+
if (self.ismaster.msg === 'isdbgrid') {
|
|
336
|
+
self._type = 'mongos';
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Have we defined self monitoring
|
|
340
|
+
if (self.s.monitoring) {
|
|
341
|
+
self.monitoringProcessId = setTimeout(monitoringProcess(self), self.s.monitoringInterval);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Emit server description changed if something listening
|
|
345
|
+
sdam.emitServerDescriptionChanged(self, {
|
|
346
|
+
address: self.name,
|
|
347
|
+
arbiters: [],
|
|
348
|
+
hosts: [],
|
|
349
|
+
passives: [],
|
|
350
|
+
type: sdam.getTopologyType(self)
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
if (!self.s.inTopology) {
|
|
354
|
+
// Emit topology description changed if something listening
|
|
355
|
+
sdam.emitTopologyDescriptionChanged(self, {
|
|
356
|
+
topologyType: 'Single',
|
|
357
|
+
servers: [
|
|
358
|
+
{
|
|
359
|
+
address: self.name,
|
|
360
|
+
arbiters: [],
|
|
361
|
+
hosts: [],
|
|
362
|
+
passives: [],
|
|
363
|
+
type: sdam.getTopologyType(self)
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Log the ismaster if available
|
|
370
|
+
if (self.s.logger.isInfo()) {
|
|
371
|
+
self.s.logger.info(
|
|
372
|
+
f('server %s connected with ismaster [%s]', self.name, JSON.stringify(self.ismaster))
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Emit connect
|
|
377
|
+
self.emit('connect', self);
|
|
378
|
+
} else if (
|
|
379
|
+
event === 'error' ||
|
|
380
|
+
event === 'parseError' ||
|
|
381
|
+
event === 'close' ||
|
|
382
|
+
event === 'timeout' ||
|
|
383
|
+
event === 'reconnect' ||
|
|
384
|
+
event === 'attemptReconnect' ||
|
|
385
|
+
'reconnectFailed'
|
|
386
|
+
) {
|
|
387
|
+
// Remove server instance from accounting
|
|
388
|
+
if (
|
|
389
|
+
serverAccounting &&
|
|
390
|
+
['close', 'timeout', 'error', 'parseError', 'reconnectFailed'].indexOf(event) !== -1
|
|
391
|
+
) {
|
|
392
|
+
// Emit toplogy opening event if not in topology
|
|
393
|
+
if (!self.s.inTopology) {
|
|
394
|
+
self.emit('topologyOpening', { topologyId: self.id });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
delete servers[self.id];
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (event === 'close') {
|
|
401
|
+
// Closing emits a server description changed event going to unknown.
|
|
402
|
+
sdam.emitServerDescriptionChanged(self, {
|
|
403
|
+
address: self.name,
|
|
404
|
+
arbiters: [],
|
|
405
|
+
hosts: [],
|
|
406
|
+
passives: [],
|
|
407
|
+
type: 'Unknown'
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Reconnect failed return error
|
|
412
|
+
if (event === 'reconnectFailed') {
|
|
413
|
+
self.emit('reconnectFailed', err);
|
|
414
|
+
// Emit error if any listeners
|
|
415
|
+
if (self.listeners('error').length > 0) {
|
|
416
|
+
self.emit('error', err);
|
|
417
|
+
}
|
|
418
|
+
// Terminate
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// On first connect fail
|
|
423
|
+
if (
|
|
424
|
+
['disconnected', 'connecting'].indexOf(self.s.pool.state) !== -1 &&
|
|
425
|
+
self.initialConnect &&
|
|
426
|
+
['close', 'timeout', 'error', 'parseError'].indexOf(event) !== -1
|
|
427
|
+
) {
|
|
428
|
+
self.initialConnect = false;
|
|
429
|
+
return self.emit(
|
|
430
|
+
'error',
|
|
431
|
+
new MongoNetworkError(
|
|
432
|
+
f('failed to connect to server [%s] on first connect [%s]', self.name, err)
|
|
433
|
+
)
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Reconnect event, emit the server
|
|
438
|
+
if (event === 'reconnect') {
|
|
439
|
+
// Reconnecting emits a server description changed event going from unknown to the
|
|
440
|
+
// current server type.
|
|
441
|
+
sdam.emitServerDescriptionChanged(self, {
|
|
442
|
+
address: self.name,
|
|
443
|
+
arbiters: [],
|
|
444
|
+
hosts: [],
|
|
445
|
+
passives: [],
|
|
446
|
+
type: sdam.getTopologyType(self)
|
|
447
|
+
});
|
|
448
|
+
return self.emit(event, self);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Emit the event
|
|
452
|
+
self.emit(event, err);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Initiate server connect
|
|
459
|
+
*/
|
|
460
|
+
Server.prototype.connect = function(options) {
|
|
461
|
+
var self = this;
|
|
462
|
+
options = options || {};
|
|
463
|
+
|
|
464
|
+
// Set the connections
|
|
465
|
+
if (serverAccounting) servers[this.id] = this;
|
|
466
|
+
|
|
467
|
+
// Do not allow connect to be called on anything that's not disconnected
|
|
468
|
+
if (self.s.pool && !self.s.pool.isDisconnected() && !self.s.pool.isDestroyed()) {
|
|
469
|
+
throw new MongoError(f('server instance in invalid state %s', self.s.pool.state));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Create a pool
|
|
473
|
+
self.s.pool = new Pool(this, Object.assign(self.s.options, options, { bson: this.s.bson }));
|
|
474
|
+
|
|
475
|
+
// Set up listeners
|
|
476
|
+
self.s.pool.on('close', eventHandler(self, 'close'));
|
|
477
|
+
self.s.pool.on('error', eventHandler(self, 'error'));
|
|
478
|
+
self.s.pool.on('timeout', eventHandler(self, 'timeout'));
|
|
479
|
+
self.s.pool.on('parseError', eventHandler(self, 'parseError'));
|
|
480
|
+
self.s.pool.on('connect', eventHandler(self, 'connect'));
|
|
481
|
+
self.s.pool.on('reconnect', eventHandler(self, 'reconnect'));
|
|
482
|
+
self.s.pool.on('reconnectFailed', eventHandler(self, 'reconnectFailed'));
|
|
483
|
+
|
|
484
|
+
// Set up listeners for command monitoring
|
|
485
|
+
relayEvents(self.s.pool, self, ['commandStarted', 'commandSucceeded', 'commandFailed']);
|
|
486
|
+
|
|
487
|
+
// Emit toplogy opening event if not in topology
|
|
488
|
+
if (!self.s.inTopology) {
|
|
489
|
+
this.emit('topologyOpening', { topologyId: self.id });
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Emit opening server event
|
|
493
|
+
self.emit('serverOpening', {
|
|
494
|
+
topologyId: self.s.topologyId !== -1 ? self.s.topologyId : self.id,
|
|
495
|
+
address: self.name
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
self.s.pool.connect();
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Authenticate the topology.
|
|
503
|
+
* @method
|
|
504
|
+
* @param {MongoCredentials} credentials The credentials for authentication we are using
|
|
505
|
+
* @param {authResultCallback} callback A callback function
|
|
506
|
+
*/
|
|
507
|
+
Server.prototype.auth = function(credentials, callback) {
|
|
508
|
+
if (typeof callback === 'function') callback(null, null);
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* Get the server description
|
|
513
|
+
* @method
|
|
514
|
+
* @return {object}
|
|
515
|
+
*/
|
|
516
|
+
Server.prototype.getDescription = function() {
|
|
517
|
+
var ismaster = this.ismaster || {};
|
|
518
|
+
var description = {
|
|
519
|
+
type: sdam.getTopologyType(this),
|
|
520
|
+
address: this.name
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
// Add fields if available
|
|
524
|
+
if (ismaster.hosts) description.hosts = ismaster.hosts;
|
|
525
|
+
if (ismaster.arbiters) description.arbiters = ismaster.arbiters;
|
|
526
|
+
if (ismaster.passives) description.passives = ismaster.passives;
|
|
527
|
+
if (ismaster.setName) description.setName = ismaster.setName;
|
|
528
|
+
return description;
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Returns the last known ismaster document for this server
|
|
533
|
+
* @method
|
|
534
|
+
* @return {object}
|
|
535
|
+
*/
|
|
536
|
+
Server.prototype.lastIsMaster = function() {
|
|
537
|
+
return this.ismaster;
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Unref all connections belong to this server
|
|
542
|
+
* @method
|
|
543
|
+
*/
|
|
544
|
+
Server.prototype.unref = function() {
|
|
545
|
+
this.s.pool.unref();
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Figure out if the server is connected
|
|
550
|
+
* @method
|
|
551
|
+
* @return {boolean}
|
|
552
|
+
*/
|
|
553
|
+
Server.prototype.isConnected = function() {
|
|
554
|
+
if (!this.s.pool) return false;
|
|
555
|
+
return this.s.pool.isConnected();
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Figure out if the server instance was destroyed by calling destroy
|
|
560
|
+
* @method
|
|
561
|
+
* @return {boolean}
|
|
562
|
+
*/
|
|
563
|
+
Server.prototype.isDestroyed = function() {
|
|
564
|
+
if (!this.s.pool) return false;
|
|
565
|
+
return this.s.pool.isDestroyed();
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
function basicWriteValidations(self) {
|
|
569
|
+
if (!self.s.pool) return new MongoError('server instance is not connected');
|
|
570
|
+
if (self.s.pool.isDestroyed()) return new MongoError('server instance pool was destroyed');
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function basicReadValidations(self, options) {
|
|
574
|
+
basicWriteValidations(self, options);
|
|
575
|
+
|
|
576
|
+
if (options.readPreference && !(options.readPreference instanceof ReadPreference)) {
|
|
577
|
+
throw new Error('readPreference must be an instance of ReadPreference');
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Execute a command
|
|
583
|
+
* @method
|
|
584
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
585
|
+
* @param {object} cmd The command hash
|
|
586
|
+
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
|
|
587
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
588
|
+
* @param {Boolean} [options.checkKeys=false] Specify if the bson parser should validate keys.
|
|
589
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
590
|
+
* @param {Boolean} [options.fullResult=false] Return the full envelope instead of just the result document.
|
|
591
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
592
|
+
* @param {opResultCallback} callback A callback function
|
|
593
|
+
*/
|
|
594
|
+
Server.prototype.command = function(ns, cmd, options, callback) {
|
|
595
|
+
var self = this;
|
|
596
|
+
if (typeof options === 'function') {
|
|
597
|
+
(callback = options), (options = {}), (options = options || {});
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
var result = basicReadValidations(self, options);
|
|
601
|
+
if (result) return callback(result);
|
|
602
|
+
|
|
603
|
+
// Clone the options
|
|
604
|
+
options = Object.assign({}, options, { wireProtocolCommand: false });
|
|
605
|
+
|
|
606
|
+
// Debug log
|
|
607
|
+
if (self.s.logger.isDebug())
|
|
608
|
+
self.s.logger.debug(
|
|
609
|
+
f(
|
|
610
|
+
'executing command [%s] against %s',
|
|
611
|
+
JSON.stringify({
|
|
612
|
+
ns: ns,
|
|
613
|
+
cmd: cmd,
|
|
614
|
+
options: debugOptions(debugFields, options)
|
|
615
|
+
}),
|
|
616
|
+
self.name
|
|
617
|
+
)
|
|
618
|
+
);
|
|
619
|
+
|
|
620
|
+
// If we are not connected or have a disconnectHandler specified
|
|
621
|
+
if (disconnectHandler(self, 'command', ns, cmd, options, callback)) return;
|
|
622
|
+
|
|
623
|
+
// error if collation not supported
|
|
624
|
+
if (collationNotSupported(this, cmd)) {
|
|
625
|
+
return callback(new MongoError(`server ${this.name} does not support collation`));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
wireProtocol.command(self, ns, cmd, options, callback);
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Execute a query against the server
|
|
633
|
+
*
|
|
634
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
635
|
+
* @param {object} cmd The command document for the query
|
|
636
|
+
* @param {object} options Optional settings
|
|
637
|
+
* @param {function} callback
|
|
638
|
+
*/
|
|
639
|
+
Server.prototype.query = function(ns, cmd, cursorState, options, callback) {
|
|
640
|
+
wireProtocol.query(this, ns, cmd, cursorState, options, callback);
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Execute a `getMore` against the server
|
|
645
|
+
*
|
|
646
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
647
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
648
|
+
* @param {object} options Optional settings
|
|
649
|
+
* @param {function} callback
|
|
650
|
+
*/
|
|
651
|
+
Server.prototype.getMore = function(ns, cursorState, batchSize, options, callback) {
|
|
652
|
+
wireProtocol.getMore(this, ns, cursorState, batchSize, options, callback);
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Execute a `killCursors` command against the server
|
|
657
|
+
*
|
|
658
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
659
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
660
|
+
* @param {function} callback
|
|
661
|
+
*/
|
|
662
|
+
Server.prototype.killCursors = function(ns, cursorState, callback) {
|
|
663
|
+
wireProtocol.killCursors(this, ns, cursorState, callback);
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Insert one or more documents
|
|
668
|
+
* @method
|
|
669
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
670
|
+
* @param {array} ops An array of documents to insert
|
|
671
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
672
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
673
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
674
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
675
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
676
|
+
* @param {opResultCallback} callback A callback function
|
|
677
|
+
*/
|
|
678
|
+
Server.prototype.insert = function(ns, ops, options, callback) {
|
|
679
|
+
var self = this;
|
|
680
|
+
if (typeof options === 'function') {
|
|
681
|
+
(callback = options), (options = {}), (options = options || {});
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
var result = basicWriteValidations(self, options);
|
|
685
|
+
if (result) return callback(result);
|
|
686
|
+
|
|
687
|
+
// If we are not connected or have a disconnectHandler specified
|
|
688
|
+
if (disconnectHandler(self, 'insert', ns, ops, options, callback)) return;
|
|
689
|
+
|
|
690
|
+
// Setup the docs as an array
|
|
691
|
+
ops = Array.isArray(ops) ? ops : [ops];
|
|
692
|
+
|
|
693
|
+
// Execute write
|
|
694
|
+
return wireProtocol.insert(self, ns, ops, options, callback);
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Perform one or more update operations
|
|
699
|
+
* @method
|
|
700
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
701
|
+
* @param {array} ops An array of updates
|
|
702
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
703
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
704
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
705
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
706
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
707
|
+
* @param {opResultCallback} callback A callback function
|
|
708
|
+
*/
|
|
709
|
+
Server.prototype.update = function(ns, ops, options, callback) {
|
|
710
|
+
var self = this;
|
|
711
|
+
if (typeof options === 'function') {
|
|
712
|
+
(callback = options), (options = {}), (options = options || {});
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
var result = basicWriteValidations(self, options);
|
|
716
|
+
if (result) return callback(result);
|
|
717
|
+
|
|
718
|
+
// If we are not connected or have a disconnectHandler specified
|
|
719
|
+
if (disconnectHandler(self, 'update', ns, ops, options, callback)) return;
|
|
720
|
+
|
|
721
|
+
// error if collation not supported
|
|
722
|
+
if (collationNotSupported(this, options)) {
|
|
723
|
+
return callback(new MongoError(`server ${this.name} does not support collation`));
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Setup the docs as an array
|
|
727
|
+
ops = Array.isArray(ops) ? ops : [ops];
|
|
728
|
+
// Execute write
|
|
729
|
+
return wireProtocol.update(self, ns, ops, options, callback);
|
|
730
|
+
};
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* Perform one or more remove operations
|
|
734
|
+
* @method
|
|
735
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
736
|
+
* @param {array} ops An array of removes
|
|
737
|
+
* @param {boolean} [options.ordered=true] Execute in order or out of order
|
|
738
|
+
* @param {object} [options.writeConcern={}] Write concern for the operation
|
|
739
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
740
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
741
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
742
|
+
* @param {opResultCallback} callback A callback function
|
|
743
|
+
*/
|
|
744
|
+
Server.prototype.remove = function(ns, ops, options, callback) {
|
|
745
|
+
var self = this;
|
|
746
|
+
if (typeof options === 'function') {
|
|
747
|
+
(callback = options), (options = {}), (options = options || {});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
var result = basicWriteValidations(self, options);
|
|
751
|
+
if (result) return callback(result);
|
|
752
|
+
|
|
753
|
+
// If we are not connected or have a disconnectHandler specified
|
|
754
|
+
if (disconnectHandler(self, 'remove', ns, ops, options, callback)) return;
|
|
755
|
+
|
|
756
|
+
// error if collation not supported
|
|
757
|
+
if (collationNotSupported(this, options)) {
|
|
758
|
+
return callback(new MongoError(`server ${this.name} does not support collation`));
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Setup the docs as an array
|
|
762
|
+
ops = Array.isArray(ops) ? ops : [ops];
|
|
763
|
+
// Execute write
|
|
764
|
+
return wireProtocol.remove(self, ns, ops, options, callback);
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Get a new cursor
|
|
769
|
+
* @method
|
|
770
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
771
|
+
* @param {object|Long} cmd Can be either a command returning a cursor or a cursorId
|
|
772
|
+
* @param {object} [options] Options for the cursor
|
|
773
|
+
* @param {object} [options.batchSize=0] Batchsize for the operation
|
|
774
|
+
* @param {array} [options.documents=[]] Initial documents list for cursor
|
|
775
|
+
* @param {ReadPreference} [options.readPreference] Specify read preference if command supports it
|
|
776
|
+
* @param {Boolean} [options.serializeFunctions=false] Specify if functions on an object should be serialized.
|
|
777
|
+
* @param {Boolean} [options.ignoreUndefined=false] Specify if the BSON serializer should ignore undefined fields.
|
|
778
|
+
* @param {ClientSession} [options.session=null] Session to use for the operation
|
|
779
|
+
* @param {object} [options.topology] The internal topology of the created cursor
|
|
780
|
+
* @returns {Cursor}
|
|
781
|
+
*/
|
|
782
|
+
Server.prototype.cursor = function(ns, cmd, options) {
|
|
783
|
+
options = options || {};
|
|
784
|
+
const topology = options.topology || this;
|
|
785
|
+
|
|
786
|
+
// Set up final cursor type
|
|
787
|
+
var FinalCursor = options.cursorFactory || this.s.Cursor;
|
|
788
|
+
|
|
789
|
+
// Return the cursor
|
|
790
|
+
return new FinalCursor(topology, ns, cmd, options);
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Compare two server instances
|
|
795
|
+
* @method
|
|
796
|
+
* @param {Server} server Server to compare equality against
|
|
797
|
+
* @return {boolean}
|
|
798
|
+
*/
|
|
799
|
+
Server.prototype.equals = function(server) {
|
|
800
|
+
if (typeof server === 'string') return this.name.toLowerCase() === server.toLowerCase();
|
|
801
|
+
if (server.name) return this.name.toLowerCase() === server.name.toLowerCase();
|
|
802
|
+
return false;
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* All raw connections
|
|
807
|
+
* @method
|
|
808
|
+
* @return {Connection[]}
|
|
809
|
+
*/
|
|
810
|
+
Server.prototype.connections = function() {
|
|
811
|
+
return this.s.pool.allConnections();
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Selects a server
|
|
816
|
+
* @method
|
|
817
|
+
* @param {function} selector Unused
|
|
818
|
+
* @param {ReadPreference} [options.readPreference] Unused
|
|
819
|
+
* @param {ClientSession} [options.session] Unused
|
|
820
|
+
* @return {Server}
|
|
821
|
+
*/
|
|
822
|
+
Server.prototype.selectServer = function(selector, options, callback) {
|
|
823
|
+
if (typeof selector === 'function' && typeof callback === 'undefined')
|
|
824
|
+
(callback = selector), (selector = undefined), (options = {});
|
|
825
|
+
if (typeof options === 'function')
|
|
826
|
+
(callback = options), (options = selector), (selector = undefined);
|
|
827
|
+
|
|
828
|
+
callback(null, this);
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
var listeners = ['close', 'error', 'timeout', 'parseError', 'connect'];
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Destroy the server connection
|
|
835
|
+
* @method
|
|
836
|
+
* @param {boolean} [options.emitClose=false] Emit close event on destroy
|
|
837
|
+
* @param {boolean} [options.emitDestroy=false] Emit destroy event on destroy
|
|
838
|
+
* @param {boolean} [options.force=false] Force destroy the pool
|
|
839
|
+
*/
|
|
840
|
+
Server.prototype.destroy = function(options, callback) {
|
|
841
|
+
if (this._destroyed) {
|
|
842
|
+
if (typeof callback === 'function') callback(null, null);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
options = options || {};
|
|
847
|
+
var self = this;
|
|
848
|
+
|
|
849
|
+
// Set the connections
|
|
850
|
+
if (serverAccounting) delete servers[this.id];
|
|
851
|
+
|
|
852
|
+
// Destroy the monitoring process if any
|
|
853
|
+
if (this.monitoringProcessId) {
|
|
854
|
+
clearTimeout(this.monitoringProcessId);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// No pool, return
|
|
858
|
+
if (!self.s.pool) {
|
|
859
|
+
this._destroyed = true;
|
|
860
|
+
if (typeof callback === 'function') callback(null, null);
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Emit close event
|
|
865
|
+
if (options.emitClose) {
|
|
866
|
+
self.emit('close', self);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// Emit destroy event
|
|
870
|
+
if (options.emitDestroy) {
|
|
871
|
+
self.emit('destroy', self);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// Remove all listeners
|
|
875
|
+
listeners.forEach(function(event) {
|
|
876
|
+
self.s.pool.removeAllListeners(event);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
// Emit opening server event
|
|
880
|
+
if (self.listeners('serverClosed').length > 0)
|
|
881
|
+
self.emit('serverClosed', {
|
|
882
|
+
topologyId: self.s.topologyId !== -1 ? self.s.topologyId : self.id,
|
|
883
|
+
address: self.name
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
// Emit toplogy opening event if not in topology
|
|
887
|
+
if (self.listeners('topologyClosed').length > 0 && !self.s.inTopology) {
|
|
888
|
+
self.emit('topologyClosed', { topologyId: self.id });
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (self.s.logger.isDebug()) {
|
|
892
|
+
self.s.logger.debug(f('destroy called on server %s', self.name));
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// Destroy the pool
|
|
896
|
+
this.s.pool.destroy(options.force, callback);
|
|
897
|
+
this._destroyed = true;
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* A server connect event, used to verify that the connection is up and running
|
|
902
|
+
*
|
|
903
|
+
* @event Server#connect
|
|
904
|
+
* @type {Server}
|
|
905
|
+
*/
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* A server reconnect event, used to verify that the server topology has reconnected
|
|
909
|
+
*
|
|
910
|
+
* @event Server#reconnect
|
|
911
|
+
* @type {Server}
|
|
912
|
+
*/
|
|
913
|
+
|
|
914
|
+
/**
|
|
915
|
+
* A server opening SDAM monitoring event
|
|
916
|
+
*
|
|
917
|
+
* @event Server#serverOpening
|
|
918
|
+
* @type {object}
|
|
919
|
+
*/
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* A server closed SDAM monitoring event
|
|
923
|
+
*
|
|
924
|
+
* @event Server#serverClosed
|
|
925
|
+
* @type {object}
|
|
926
|
+
*/
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* A server description SDAM change monitoring event
|
|
930
|
+
*
|
|
931
|
+
* @event Server#serverDescriptionChanged
|
|
932
|
+
* @type {object}
|
|
933
|
+
*/
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* A topology open SDAM event
|
|
937
|
+
*
|
|
938
|
+
* @event Server#topologyOpening
|
|
939
|
+
* @type {object}
|
|
940
|
+
*/
|
|
941
|
+
|
|
942
|
+
/**
|
|
943
|
+
* A topology closed SDAM event
|
|
944
|
+
*
|
|
945
|
+
* @event Server#topologyClosed
|
|
946
|
+
* @type {object}
|
|
947
|
+
*/
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* A topology structure SDAM change event
|
|
951
|
+
*
|
|
952
|
+
* @event Server#topologyDescriptionChanged
|
|
953
|
+
* @type {object}
|
|
954
|
+
*/
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Server reconnect failed
|
|
958
|
+
*
|
|
959
|
+
* @event Server#reconnectFailed
|
|
960
|
+
* @type {Error}
|
|
961
|
+
*/
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Server connection pool closed
|
|
965
|
+
*
|
|
966
|
+
* @event Server#close
|
|
967
|
+
* @type {object}
|
|
968
|
+
*/
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Server connection pool caused an error
|
|
972
|
+
*
|
|
973
|
+
* @event Server#error
|
|
974
|
+
* @type {Error}
|
|
975
|
+
*/
|
|
976
|
+
|
|
977
|
+
/**
|
|
978
|
+
* Server destroyed was called
|
|
979
|
+
*
|
|
980
|
+
* @event Server#destroy
|
|
981
|
+
* @type {Server}
|
|
982
|
+
*/
|
|
983
|
+
|
|
984
|
+
module.exports = Server;
|