mongodb 3.3.0-beta1 → 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/lib/aggregation_cursor.js +3 -1
- package/lib/change_stream.js +183 -71
- package/lib/collection.js +8 -9
- package/lib/command_cursor.js +6 -4
- package/lib/core/connection/connect.js +1 -1
- package/lib/core/connection/pool.js +66 -41
- package/lib/core/cursor.js +70 -60
- package/lib/core/error.js +24 -1
- package/lib/core/sdam/server.js +84 -9
- package/lib/core/sdam/server_description.js +14 -0
- package/lib/core/sdam/topology.js +17 -4
- package/lib/core/sdam/topology_description.js +6 -14
- package/lib/core/topologies/mongos.js +1 -1
- package/lib/core/topologies/replset.js +1 -1
- package/lib/core/topologies/server.js +36 -1
- package/lib/core/utils.js +38 -1
- package/lib/core/wireprotocol/command.js +2 -2
- package/lib/cursor.js +7 -5
- package/lib/db.js +7 -1
- package/lib/error.js +10 -8
- package/lib/mongo_client.js +9 -13
- package/lib/operations/aggregate.js +17 -9
- package/lib/operations/close.js +47 -0
- package/lib/operations/collection_ops.js +4 -0
- package/lib/operations/command.js +2 -1
- package/lib/operations/command_v2.js +43 -0
- package/lib/operations/connect.js +83 -9
- package/lib/operations/create_collection.js +1 -0
- package/lib/operations/distinct.js +20 -21
- package/lib/operations/drop.js +1 -0
- package/lib/operations/execute_operation.js +81 -2
- package/lib/operations/explain.js +0 -4
- package/lib/operations/operation.js +3 -1
- package/package.json +1 -1
- package/lib/operations/mongo_client_ops.js +0 -731
package/lib/core/cursor.js
CHANGED
|
@@ -7,7 +7,9 @@ const MongoNetworkError = require('./error').MongoNetworkError;
|
|
|
7
7
|
const mongoErrorContextSymbol = require('./error').mongoErrorContextSymbol;
|
|
8
8
|
const f = require('util').format;
|
|
9
9
|
const collationNotSupported = require('./utils').collationNotSupported;
|
|
10
|
-
const
|
|
10
|
+
const ReadPreference = require('./topologies/read_preference');
|
|
11
|
+
const isUnifiedTopology = require('./utils').isUnifiedTopology;
|
|
12
|
+
|
|
11
13
|
const BSON = retrieveBSON();
|
|
12
14
|
const Long = BSON.Long;
|
|
13
15
|
|
|
@@ -29,7 +31,7 @@ const Long = BSON.Long;
|
|
|
29
31
|
/**
|
|
30
32
|
* Creates a new Cursor, not to be used directly
|
|
31
33
|
* @class
|
|
32
|
-
* @param {object}
|
|
34
|
+
* @param {object} topology The server topology instance.
|
|
33
35
|
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
34
36
|
* @param {{object}|Long} cmd The selector (can be a command or a cursorId)
|
|
35
37
|
* @param {object} [options=null] Optional settings.
|
|
@@ -38,14 +40,12 @@ const Long = BSON.Long;
|
|
|
38
40
|
* @param {object} [options.transforms=null] Transform methods for the cursor results
|
|
39
41
|
* @param {function} [options.transforms.query] Transform the value returned from the initial query
|
|
40
42
|
* @param {function} [options.transforms.doc] Transform each document returned from Cursor.prototype.next
|
|
41
|
-
* @param {object} topology The server topology instance.
|
|
42
|
-
* @param {object} topologyOptions The server topology options.
|
|
43
43
|
* @return {Cursor} A cursor instance
|
|
44
44
|
* @property {number} cursorBatchSize The current cursorBatchSize for the cursor
|
|
45
45
|
* @property {number} cursorLimit The current cursorLimit for the cursor
|
|
46
46
|
* @property {number} cursorSkip The current cursorSkip for the cursor
|
|
47
47
|
*/
|
|
48
|
-
var Cursor = function(
|
|
48
|
+
var Cursor = function(topology, ns, cmd, options) {
|
|
49
49
|
options = options || {};
|
|
50
50
|
|
|
51
51
|
// Cursor pool
|
|
@@ -57,7 +57,7 @@ var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
|
|
|
57
57
|
this.disconnectHandler = options.disconnectHandler;
|
|
58
58
|
|
|
59
59
|
// Set local values
|
|
60
|
-
this.bson = bson;
|
|
60
|
+
this.bson = topology.s.bson;
|
|
61
61
|
this.ns = ns;
|
|
62
62
|
this.cmd = cmd;
|
|
63
63
|
this.options = options;
|
|
@@ -87,6 +87,7 @@ var Cursor = function(bson, ns, cmd, options, topology, topologyOptions) {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// Add promoteLong to cursor state
|
|
90
|
+
const topologyOptions = topology.s.options;
|
|
90
91
|
if (typeof topologyOptions.promoteLongs === 'boolean') {
|
|
91
92
|
this.cursorState.promoteLongs = topologyOptions.promoteLongs;
|
|
92
93
|
} else if (typeof options.promoteLongs === 'boolean') {
|
|
@@ -183,7 +184,7 @@ var handleCallback = function(callback, err, result) {
|
|
|
183
184
|
};
|
|
184
185
|
|
|
185
186
|
// Internal methods
|
|
186
|
-
Cursor.prototype.
|
|
187
|
+
Cursor.prototype._getMore = function(callback) {
|
|
187
188
|
if (this.logger.isDebug())
|
|
188
189
|
this.logger.debug(f('schedule getMore call for query [%s]', JSON.stringify(this.query)));
|
|
189
190
|
|
|
@@ -196,7 +197,7 @@ Cursor.prototype._getmore = function(callback) {
|
|
|
196
197
|
batchSize = this.cursorState.limit - this.cursorState.currentLimit;
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
this.server.getMore(this.ns, this.cursorState, batchSize, this.options, callback);
|
|
200
201
|
};
|
|
201
202
|
|
|
202
203
|
/**
|
|
@@ -305,7 +306,7 @@ Cursor.prototype.kill = function(callback) {
|
|
|
305
306
|
return;
|
|
306
307
|
}
|
|
307
308
|
|
|
308
|
-
|
|
309
|
+
this.server.killCursors(this.ns, this.cursorState, callback);
|
|
309
310
|
};
|
|
310
311
|
|
|
311
312
|
/**
|
|
@@ -406,6 +407,7 @@ var _setCursorNotifiedImpl = function(self, callback) {
|
|
|
406
407
|
if (self._endSession) {
|
|
407
408
|
return self._endSession(undefined, () => callback());
|
|
408
409
|
}
|
|
410
|
+
|
|
409
411
|
return callback();
|
|
410
412
|
};
|
|
411
413
|
|
|
@@ -426,7 +428,37 @@ var nextFunction = function(self, callback) {
|
|
|
426
428
|
|
|
427
429
|
// We have just started the cursor
|
|
428
430
|
if (!self.cursorState.init) {
|
|
429
|
-
|
|
431
|
+
// Topology is not connected, save the call in the provided store to be
|
|
432
|
+
// Executed at some point when the handler deems it's reconnected
|
|
433
|
+
if (!self.topology.isConnected(self.options)) {
|
|
434
|
+
// Only need this for single server, because repl sets and mongos
|
|
435
|
+
// will always continue trying to reconnect
|
|
436
|
+
if (self.topology._type === 'server' && !self.topology.s.options.reconnect) {
|
|
437
|
+
// Reconnect is disabled, so we'll never reconnect
|
|
438
|
+
return callback(new MongoError('no connection available'));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (self.disconnectHandler != null) {
|
|
442
|
+
if (self.topology.isDestroyed()) {
|
|
443
|
+
// Topology was destroyed, so don't try to wait for it to reconnect
|
|
444
|
+
return callback(new MongoError('Topology was destroyed'));
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
self.disconnectHandler.addObjectAndMethod('cursor', self, 'next', [callback], callback);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
self._initializeCursor((err, result) => {
|
|
453
|
+
if (err || result === null) {
|
|
454
|
+
callback(err, result);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
nextFunction(self, callback);
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
return;
|
|
430
462
|
}
|
|
431
463
|
|
|
432
464
|
if (self.cursorState.limit > 0 && self.cursorState.currentLimit >= self.cursorState.limit) {
|
|
@@ -449,11 +481,11 @@ var nextFunction = function(self, callback) {
|
|
|
449
481
|
);
|
|
450
482
|
|
|
451
483
|
// Check if connection is dead and return if not possible to
|
|
452
|
-
// execute a
|
|
484
|
+
// execute a getMore on this connection
|
|
453
485
|
if (isConnectionDead(self, callback)) return;
|
|
454
486
|
|
|
455
487
|
// Execute the next get more
|
|
456
|
-
self.
|
|
488
|
+
self._getMore(function(err, doc, connection) {
|
|
457
489
|
if (err) {
|
|
458
490
|
if (err instanceof MongoError) {
|
|
459
491
|
err[mongoErrorContextSymbol].isGetMore = true;
|
|
@@ -552,31 +584,21 @@ var nextFunction = function(self, callback) {
|
|
|
552
584
|
}
|
|
553
585
|
};
|
|
554
586
|
|
|
555
|
-
function
|
|
556
|
-
|
|
557
|
-
// Executed at some point when the handler deems it's reconnected
|
|
558
|
-
if (!cursor.topology.isConnected(cursor.options)) {
|
|
559
|
-
// Only need this for single server, because repl sets and mongos
|
|
560
|
-
// will always continue trying to reconnect
|
|
561
|
-
if (cursor.topology._type === 'server' && !cursor.topology.s.options.reconnect) {
|
|
562
|
-
// Reconnect is disabled, so we'll never reconnect
|
|
563
|
-
return callback(new MongoError('no connection available'));
|
|
564
|
-
}
|
|
587
|
+
Cursor.prototype._initializeCursor = function(callback) {
|
|
588
|
+
const cursor = this;
|
|
565
589
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
590
|
+
// NOTE: this goes away once cursors use `executeOperation`
|
|
591
|
+
if (isUnifiedTopology(cursor.topology) && cursor.topology.shouldCheckForSessionSupport()) {
|
|
592
|
+
cursor.topology.selectServer(ReadPreference.primaryPreferred, err => {
|
|
593
|
+
if (err) {
|
|
594
|
+
callback(err);
|
|
595
|
+
return;
|
|
570
596
|
}
|
|
571
597
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
[callback],
|
|
577
|
-
callback
|
|
578
|
-
);
|
|
579
|
-
}
|
|
598
|
+
cursor.next(callback);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
return;
|
|
580
602
|
}
|
|
581
603
|
|
|
582
604
|
// Very explicitly choose what is passed to selectServer
|
|
@@ -604,7 +626,7 @@ function initializeCursor(cursor, callback) {
|
|
|
604
626
|
return callback(new MongoError(`server ${cursor.server.name} does not support collation`));
|
|
605
627
|
}
|
|
606
628
|
|
|
607
|
-
function done() {
|
|
629
|
+
function done(err, result) {
|
|
608
630
|
if (
|
|
609
631
|
cursor.cursorState.cursorId &&
|
|
610
632
|
cursor.cursorState.cursorId.isZero() &&
|
|
@@ -623,7 +645,7 @@ function initializeCursor(cursor, callback) {
|
|
|
623
645
|
return setCursorNotified(cursor, callback);
|
|
624
646
|
}
|
|
625
647
|
|
|
626
|
-
|
|
648
|
+
callback(err, result);
|
|
627
649
|
}
|
|
628
650
|
|
|
629
651
|
// NOTE: this is a special internal method for cloning a cursor, consider removing
|
|
@@ -632,11 +654,13 @@ function initializeCursor(cursor, callback) {
|
|
|
632
654
|
}
|
|
633
655
|
|
|
634
656
|
const queryCallback = (err, r) => {
|
|
635
|
-
if (err)
|
|
657
|
+
if (err) {
|
|
658
|
+
return done(err);
|
|
659
|
+
}
|
|
636
660
|
|
|
637
661
|
const result = r.message;
|
|
638
662
|
if (result.queryFailure) {
|
|
639
|
-
return
|
|
663
|
+
return done(new MongoError(result.documents[0]), null);
|
|
640
664
|
}
|
|
641
665
|
|
|
642
666
|
// Check if we have a command cursor
|
|
@@ -651,7 +675,7 @@ function initializeCursor(cursor, callback) {
|
|
|
651
675
|
) {
|
|
652
676
|
// We have an error document, return the error
|
|
653
677
|
if (result.documents[0]['$err'] || result.documents[0]['errmsg']) {
|
|
654
|
-
return
|
|
678
|
+
return done(new MongoError(result.documents[0]), null);
|
|
655
679
|
}
|
|
656
680
|
|
|
657
681
|
// We have a cursor document
|
|
@@ -665,19 +689,20 @@ function initializeCursor(cursor, callback) {
|
|
|
665
689
|
cursor.cursorState.cursorId = typeof id === 'number' ? Long.fromNumber(id) : id;
|
|
666
690
|
cursor.cursorState.lastCursorId = cursor.cursorState.cursorId;
|
|
667
691
|
cursor.cursorState.operationTime = result.documents[0].operationTime;
|
|
692
|
+
|
|
668
693
|
// If we have a firstBatch set it
|
|
669
694
|
if (Array.isArray(result.documents[0].cursor.firstBatch)) {
|
|
670
695
|
cursor.cursorState.documents = result.documents[0].cursor.firstBatch; //.reverse();
|
|
671
696
|
}
|
|
672
697
|
|
|
673
698
|
// Return after processing command cursor
|
|
674
|
-
return done(result);
|
|
699
|
+
return done(null, result);
|
|
675
700
|
}
|
|
676
701
|
|
|
677
702
|
if (Array.isArray(result.documents[0].result)) {
|
|
678
703
|
cursor.cursorState.documents = result.documents[0].result;
|
|
679
704
|
cursor.cursorState.cursorId = Long.ZERO;
|
|
680
|
-
return done(result);
|
|
705
|
+
return done(null, result);
|
|
681
706
|
}
|
|
682
707
|
}
|
|
683
708
|
|
|
@@ -695,8 +720,7 @@ function initializeCursor(cursor, callback) {
|
|
|
695
720
|
cursor.cursorState.documents = cursor.cursorState.transforms.query(result);
|
|
696
721
|
}
|
|
697
722
|
|
|
698
|
-
|
|
699
|
-
done(result);
|
|
723
|
+
done(null, result);
|
|
700
724
|
};
|
|
701
725
|
|
|
702
726
|
if (cursor.logger.isDebug()) {
|
|
@@ -708,27 +732,13 @@ function initializeCursor(cursor, callback) {
|
|
|
708
732
|
}
|
|
709
733
|
|
|
710
734
|
if (cursor.cmd.find != null) {
|
|
711
|
-
|
|
712
|
-
cursor.server,
|
|
713
|
-
cursor.ns,
|
|
714
|
-
cursor.cmd,
|
|
715
|
-
cursor.cursorState,
|
|
716
|
-
cursor.options,
|
|
717
|
-
queryCallback
|
|
718
|
-
);
|
|
719
|
-
|
|
735
|
+
server.query(cursor.ns, cursor.cmd, cursor.cursorState, cursor.options, queryCallback);
|
|
720
736
|
return;
|
|
721
737
|
}
|
|
722
738
|
|
|
723
|
-
cursor.
|
|
724
|
-
cursor.server,
|
|
725
|
-
cursor.ns,
|
|
726
|
-
cursor.cmd,
|
|
727
|
-
cursor.options,
|
|
728
|
-
queryCallback
|
|
729
|
-
);
|
|
739
|
+
server.command(cursor.ns, cursor.cmd, cursor.options, queryCallback);
|
|
730
740
|
});
|
|
731
|
-
}
|
|
741
|
+
};
|
|
732
742
|
|
|
733
743
|
/**
|
|
734
744
|
* Retrieve the next document from the cursor
|
package/lib/core/error.js
CHANGED
|
@@ -152,6 +152,28 @@ function isRetryableError(error) {
|
|
|
152
152
|
);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
const SDAM_UNRECOVERABLE_ERROR_CODES = new Set([
|
|
156
|
+
91, // ShutdownInProgress
|
|
157
|
+
189, // PrimarySteppedDown
|
|
158
|
+
10107, // NotMaster
|
|
159
|
+
11600, // InterruptedAtShutdown
|
|
160
|
+
11602, // InterruptedDueToReplStateChange
|
|
161
|
+
13435, // NotMasterNoSlaveOk
|
|
162
|
+
13436 // NotMasterOrSecondary
|
|
163
|
+
]);
|
|
164
|
+
/**
|
|
165
|
+
* Determines whether an error is a "node is recovering" error or a "not master" error for SDAM retryability.
|
|
166
|
+
* See https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#not-master-and-node-is-recovering
|
|
167
|
+
* @param {MongoError|Error} error
|
|
168
|
+
*/
|
|
169
|
+
function isSDAMUnrecoverableError(error) {
|
|
170
|
+
return (
|
|
171
|
+
SDAM_UNRECOVERABLE_ERROR_CODES.has(error.code) ||
|
|
172
|
+
(error.message &&
|
|
173
|
+
(error.message.match(/not master/) || error.message.match(/node is recovering/)))
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
155
177
|
module.exports = {
|
|
156
178
|
MongoError,
|
|
157
179
|
MongoNetworkError,
|
|
@@ -159,5 +181,6 @@ module.exports = {
|
|
|
159
181
|
MongoTimeoutError,
|
|
160
182
|
MongoWriteConcernError,
|
|
161
183
|
mongoErrorContextSymbol,
|
|
162
|
-
isRetryableError
|
|
184
|
+
isRetryableError,
|
|
185
|
+
isSDAMUnrecoverableError
|
|
163
186
|
};
|
package/lib/core/sdam/server.js
CHANGED
|
@@ -14,6 +14,7 @@ const MongoParseError = require('../error').MongoParseError;
|
|
|
14
14
|
const MongoNetworkError = require('../error').MongoNetworkError;
|
|
15
15
|
const collationNotSupported = require('../utils').collationNotSupported;
|
|
16
16
|
const debugOptions = require('../connection/utils').debugOptions;
|
|
17
|
+
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
|
|
17
18
|
|
|
18
19
|
// Used for filtering out fields for logging
|
|
19
20
|
const DEBUG_FIELDS = [
|
|
@@ -95,6 +96,13 @@ class Server extends EventEmitter {
|
|
|
95
96
|
return this.s.description.address;
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
get autoEncrypter() {
|
|
100
|
+
if (this.s.options && this.s.options.autoEncrypter) {
|
|
101
|
+
return this.s.options.autoEncrypter;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
98
106
|
/**
|
|
99
107
|
* Initiate server connect
|
|
100
108
|
*/
|
|
@@ -154,13 +162,16 @@ class Server extends EventEmitter {
|
|
|
154
162
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
155
163
|
options = Object.assign({}, { force: false }, options);
|
|
156
164
|
|
|
157
|
-
|
|
165
|
+
const done = err => {
|
|
166
|
+
this.emit('closed');
|
|
158
167
|
this.s.state = STATE_DISCONNECTED;
|
|
159
168
|
if (typeof callback === 'function') {
|
|
160
|
-
callback(
|
|
169
|
+
callback(err, null);
|
|
161
170
|
}
|
|
171
|
+
};
|
|
162
172
|
|
|
163
|
-
|
|
173
|
+
if (!this.s.pool) {
|
|
174
|
+
return done();
|
|
164
175
|
}
|
|
165
176
|
|
|
166
177
|
['close', 'error', 'timeout', 'parseError', 'connect'].forEach(event => {
|
|
@@ -171,10 +182,7 @@ class Server extends EventEmitter {
|
|
|
171
182
|
clearTimeout(this.s.monitorId);
|
|
172
183
|
}
|
|
173
184
|
|
|
174
|
-
this.s.pool.destroy(options.force,
|
|
175
|
-
this.s.state = STATE_DISCONNECTED;
|
|
176
|
-
callback(err);
|
|
177
|
-
});
|
|
185
|
+
this.s.pool.destroy(options.force, done);
|
|
178
186
|
}
|
|
179
187
|
|
|
180
188
|
/**
|
|
@@ -231,7 +239,68 @@ class Server extends EventEmitter {
|
|
|
231
239
|
return;
|
|
232
240
|
}
|
|
233
241
|
|
|
234
|
-
wireProtocol.command(this, ns, cmd, options,
|
|
242
|
+
wireProtocol.command(this, ns, cmd, options, (err, result) => {
|
|
243
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
244
|
+
this.emit('error', err);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
callback(err, result);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Execute a query against the server
|
|
253
|
+
*
|
|
254
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
255
|
+
* @param {object} cmd The command document for the query
|
|
256
|
+
* @param {object} options Optional settings
|
|
257
|
+
* @param {function} callback
|
|
258
|
+
*/
|
|
259
|
+
query(ns, cmd, cursorState, options, callback) {
|
|
260
|
+
wireProtocol.query(this, ns, cmd, cursorState, options, (err, result) => {
|
|
261
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
262
|
+
this.emit('error', err);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
callback(err, result);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Execute a `getMore` against the server
|
|
271
|
+
*
|
|
272
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
273
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
274
|
+
* @param {object} options Optional settings
|
|
275
|
+
* @param {function} callback
|
|
276
|
+
*/
|
|
277
|
+
getMore(ns, cursorState, batchSize, options, callback) {
|
|
278
|
+
wireProtocol.getMore(this, ns, cursorState, batchSize, options, (err, result) => {
|
|
279
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
280
|
+
this.emit('error', err);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
callback(err, result);
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Execute a `killCursors` command against the server
|
|
289
|
+
*
|
|
290
|
+
* @param {string} ns The MongoDB fully qualified namespace (ex: db1.collection1)
|
|
291
|
+
* @param {object} cursorState State data associated with the cursor calling this method
|
|
292
|
+
* @param {function} callback
|
|
293
|
+
*/
|
|
294
|
+
killCursors(ns, cursorState, callback) {
|
|
295
|
+
wireProtocol.killCursors(this, ns, cursorState, (err, result) => {
|
|
296
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
297
|
+
this.emit('error', err);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (typeof callback === 'function') {
|
|
301
|
+
callback(err, result);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
235
304
|
}
|
|
236
305
|
|
|
237
306
|
/**
|
|
@@ -336,7 +405,13 @@ function executeWriteOperation(args, options, callback) {
|
|
|
336
405
|
return;
|
|
337
406
|
}
|
|
338
407
|
|
|
339
|
-
return wireProtocol[op](server, ns, ops, options,
|
|
408
|
+
return wireProtocol[op](server, ns, ops, options, (err, result) => {
|
|
409
|
+
if (err && isSDAMUnrecoverableError(err)) {
|
|
410
|
+
server.emit('error', err);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
callback(err, result);
|
|
414
|
+
});
|
|
340
415
|
}
|
|
341
416
|
|
|
342
417
|
function connectEventHandler(server) {
|
|
@@ -19,6 +19,13 @@ const WRITABLE_SERVER_TYPES = new Set([
|
|
|
19
19
|
ServerType.Mongos
|
|
20
20
|
]);
|
|
21
21
|
|
|
22
|
+
const DATA_BEARING_SERVER_TYPES = new Set([
|
|
23
|
+
ServerType.RSPrimary,
|
|
24
|
+
ServerType.RSSecondary,
|
|
25
|
+
ServerType.Mongos,
|
|
26
|
+
ServerType.Standalone
|
|
27
|
+
]);
|
|
28
|
+
|
|
22
29
|
const ISMASTER_FIELDS = [
|
|
23
30
|
'minWireVersion',
|
|
24
31
|
'maxWireVersion',
|
|
@@ -99,6 +106,13 @@ class ServerDescription {
|
|
|
99
106
|
return this.type === ServerType.RSSecondary || this.isWritable;
|
|
100
107
|
}
|
|
101
108
|
|
|
109
|
+
/**
|
|
110
|
+
* @return {Boolean} Is this server data bearing
|
|
111
|
+
*/
|
|
112
|
+
get isDataBearing() {
|
|
113
|
+
return DATA_BEARING_SERVER_TYPES.has(this.type);
|
|
114
|
+
}
|
|
115
|
+
|
|
102
116
|
/**
|
|
103
117
|
* @return {Boolean} Is this server available for writes
|
|
104
118
|
*/
|
|
@@ -19,6 +19,7 @@ const BSON = require('../connection/utils').retrieveBSON();
|
|
|
19
19
|
const createCompressionInfo = require('../topologies/shared').createCompressionInfo;
|
|
20
20
|
const isRetryableError = require('../error').isRetryableError;
|
|
21
21
|
const MongoParseError = require('../error').MongoParseError;
|
|
22
|
+
const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError;
|
|
22
23
|
const ClientSession = require('../sessions').ClientSession;
|
|
23
24
|
const createClientInfo = require('../topologies/shared').createClientInfo;
|
|
24
25
|
const MongoError = require('../error').MongoError;
|
|
@@ -390,6 +391,17 @@ class Topology extends EventEmitter {
|
|
|
390
391
|
}
|
|
391
392
|
|
|
392
393
|
// Sessions related methods
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* @return Whether the topology should initiate selection to determine session support
|
|
397
|
+
*/
|
|
398
|
+
shouldCheckForSessionSupport() {
|
|
399
|
+
return (
|
|
400
|
+
(this.description.type === TopologyType.Single && !this.description.hasKnownServers) ||
|
|
401
|
+
!this.description.hasDataBearingServers
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
393
405
|
/**
|
|
394
406
|
* @return Whether sessions are supported on the current topology
|
|
395
407
|
*/
|
|
@@ -632,7 +644,7 @@ class Topology extends EventEmitter {
|
|
|
632
644
|
const CursorClass = options.cursorFactory || this.s.Cursor;
|
|
633
645
|
translateReadPreference(options);
|
|
634
646
|
|
|
635
|
-
return new CursorClass(
|
|
647
|
+
return new CursorClass(topology, ns, cmd, options);
|
|
636
648
|
}
|
|
637
649
|
|
|
638
650
|
get clientInfo() {
|
|
@@ -919,7 +931,7 @@ function serverErrorEventHandler(server, topology) {
|
|
|
919
931
|
new monitoring.ServerClosedEvent(topology.s.id, server.description.address)
|
|
920
932
|
);
|
|
921
933
|
|
|
922
|
-
if (err instanceof MongoParseError) {
|
|
934
|
+
if (err instanceof MongoParseError || isSDAMUnrecoverableError(err)) {
|
|
923
935
|
resetServerState(server, err, { clearPool: true });
|
|
924
936
|
return;
|
|
925
937
|
}
|
|
@@ -997,10 +1009,11 @@ function resetServerState(server, error, options) {
|
|
|
997
1009
|
'descriptionReceived',
|
|
998
1010
|
new ServerDescription(server.description.address, null, { error })
|
|
999
1011
|
);
|
|
1012
|
+
server.monitor();
|
|
1000
1013
|
}
|
|
1001
1014
|
|
|
1002
|
-
if (options.clearPool && server.pool) {
|
|
1003
|
-
server.pool.reset(() => resetState());
|
|
1015
|
+
if (options.clearPool && server.s.pool) {
|
|
1016
|
+
server.s.pool.reset(() => resetState());
|
|
1004
1017
|
return;
|
|
1005
1018
|
}
|
|
1006
1019
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const ServerType = require('./server_description').ServerType;
|
|
3
3
|
const ServerDescription = require('./server_description').ServerDescription;
|
|
4
|
-
const ReadPreference = require('../topologies/read_preference');
|
|
5
4
|
const WIRE_CONSTANTS = require('../wireprotocol/constants');
|
|
6
5
|
|
|
7
6
|
// contstants related to compatability checks
|
|
@@ -258,24 +257,17 @@ class TopologyDescription {
|
|
|
258
257
|
}
|
|
259
258
|
|
|
260
259
|
/**
|
|
261
|
-
* Determines if the topology has
|
|
262
|
-
* following section for behaviour rules.
|
|
263
|
-
*
|
|
264
|
-
* @param {ReadPreference} [readPreference] An optional read preference for determining if a readable server is present
|
|
265
|
-
* @return {Boolean} Whether there is a readable server in this topology
|
|
260
|
+
* Determines if the topology description has any known servers
|
|
266
261
|
*/
|
|
267
|
-
|
|
268
|
-
|
|
262
|
+
get hasKnownServers() {
|
|
263
|
+
return Array.from(this.servers.values()).some(sd => sd.type !== ServerDescription.Unknown);
|
|
269
264
|
}
|
|
270
265
|
|
|
271
266
|
/**
|
|
272
|
-
* Determines if
|
|
273
|
-
* following section for behaviour rules.
|
|
274
|
-
*
|
|
275
|
-
* @return {Boolean} Whether there is a writable server in this topology
|
|
267
|
+
* Determines if this topology description has a data-bearing server available.
|
|
276
268
|
*/
|
|
277
|
-
|
|
278
|
-
return this.
|
|
269
|
+
get hasDataBearingServers() {
|
|
270
|
+
return Array.from(this.servers.values()).some(sd => sd.isDataBearing);
|
|
279
271
|
}
|
|
280
272
|
|
|
281
273
|
/**
|
|
@@ -1110,7 +1110,7 @@ Mongos.prototype.cursor = function(ns, cmd, options) {
|
|
|
1110
1110
|
var FinalCursor = options.cursorFactory || this.s.Cursor;
|
|
1111
1111
|
|
|
1112
1112
|
// Return the cursor
|
|
1113
|
-
return new FinalCursor(
|
|
1113
|
+
return new FinalCursor(topology, ns, cmd, options);
|
|
1114
1114
|
};
|
|
1115
1115
|
|
|
1116
1116
|
/**
|
|
@@ -1364,7 +1364,7 @@ ReplSet.prototype.cursor = function(ns, cmd, options) {
|
|
|
1364
1364
|
var FinalCursor = options.cursorFactory || this.s.Cursor;
|
|
1365
1365
|
|
|
1366
1366
|
// Return the cursor
|
|
1367
|
-
return new FinalCursor(
|
|
1367
|
+
return new FinalCursor(topology, ns, cmd, options);
|
|
1368
1368
|
};
|
|
1369
1369
|
|
|
1370
1370
|
/**
|
|
@@ -628,6 +628,41 @@ Server.prototype.command = function(ns, cmd, options, callback) {
|
|
|
628
628
|
wireProtocol.command(self, ns, cmd, options, callback);
|
|
629
629
|
};
|
|
630
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
|
+
|
|
631
666
|
/**
|
|
632
667
|
* Insert one or more documents
|
|
633
668
|
* @method
|
|
@@ -752,7 +787,7 @@ Server.prototype.cursor = function(ns, cmd, options) {
|
|
|
752
787
|
var FinalCursor = options.cursorFactory || this.s.Cursor;
|
|
753
788
|
|
|
754
789
|
// Return the cursor
|
|
755
|
-
return new FinalCursor(
|
|
790
|
+
return new FinalCursor(topology, ns, cmd, options);
|
|
756
791
|
};
|
|
757
792
|
|
|
758
793
|
/**
|