mongodb 3.5.7 → 3.5.11
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 +44 -0
- package/lib/bulk/common.js +4 -11
- package/lib/bulk/unordered.js +8 -0
- package/lib/change_stream.js +194 -145
- package/lib/cmap/connection.js +8 -4
- package/lib/cmap/connection_pool.js +11 -3
- package/lib/collection.js +2 -3
- package/lib/core/connection/apm.js +1 -1
- package/lib/core/connection/pool.js +2 -1
- package/lib/core/cursor.js +46 -59
- package/lib/core/error.js +11 -4
- package/lib/core/index.js +0 -1
- package/lib/core/sdam/monitor.js +53 -61
- package/lib/core/sdam/server.js +5 -2
- package/lib/core/sdam/server_description.js +12 -1
- package/lib/core/sdam/server_selection.js +25 -37
- package/lib/core/sdam/topology.js +4 -26
- package/lib/core/sessions.js +12 -6
- package/lib/core/topologies/read_preference.js +58 -6
- package/lib/core/topologies/replset.js +4 -4
- package/lib/core/utils.js +13 -23
- package/lib/core/wireprotocol/command.js +1 -6
- package/lib/core/wireprotocol/get_more.js +6 -1
- package/lib/cursor.js +10 -32
- package/lib/db.js +3 -3
- package/lib/error.js +26 -33
- package/lib/mongo_client.js +8 -0
- package/lib/operations/collection_ops.js +1 -2
- package/lib/operations/command.js +2 -3
- package/lib/operations/command_v2.js +7 -6
- package/lib/operations/connect.js +11 -0
- package/lib/operations/cursor_ops.js +2 -3
- package/lib/operations/db_ops.js +1 -2
- package/lib/operations/find.js +2 -2
- package/lib/operations/geo_haystack_search.js +2 -2
- package/lib/operations/map_reduce.js +2 -2
- package/lib/operations/operation.js +2 -1
- package/lib/operations/run_command.js +19 -0
- package/lib/topologies/native_topology.js +12 -2
- package/lib/topologies/topology_base.js +4 -4
- package/lib/utils.js +96 -60
- package/package.json +7 -4
|
@@ -275,7 +275,7 @@ class Topology extends EventEmitter {
|
|
|
275
275
|
// connect all known servers, then attempt server selection to connect
|
|
276
276
|
connectServers(this, Array.from(this.s.description.servers.values()));
|
|
277
277
|
|
|
278
|
-
|
|
278
|
+
ReadPreference.translate(options);
|
|
279
279
|
const readPreference = options.readPreference || ReadPreference.primary;
|
|
280
280
|
this.selectServer(readPreferenceServerSelector(readPreference), options, err => {
|
|
281
281
|
if (err) {
|
|
@@ -381,7 +381,7 @@ class Topology extends EventEmitter {
|
|
|
381
381
|
} else if (typeof selector === 'string') {
|
|
382
382
|
readPreference = new ReadPreference(selector);
|
|
383
383
|
} else {
|
|
384
|
-
|
|
384
|
+
ReadPreference.translate(options);
|
|
385
385
|
readPreference = options.readPreference || ReadPreference.primary;
|
|
386
386
|
}
|
|
387
387
|
|
|
@@ -647,7 +647,7 @@ class Topology extends EventEmitter {
|
|
|
647
647
|
(callback = options), (options = {}), (options = options || {});
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
-
|
|
650
|
+
ReadPreference.translate(options);
|
|
651
651
|
const readPreference = options.readPreference || ReadPreference.primary;
|
|
652
652
|
|
|
653
653
|
this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
|
|
@@ -708,7 +708,7 @@ class Topology extends EventEmitter {
|
|
|
708
708
|
options = options || {};
|
|
709
709
|
const topology = options.topology || this;
|
|
710
710
|
const CursorClass = options.cursorFactory || this.s.Cursor;
|
|
711
|
-
|
|
711
|
+
ReadPreference.translate(options);
|
|
712
712
|
|
|
713
713
|
return new CursorClass(topology, ns, cmd, options);
|
|
714
714
|
}
|
|
@@ -939,28 +939,6 @@ function executeWriteOperation(args, options, callback) {
|
|
|
939
939
|
});
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
-
function translateReadPreference(options) {
|
|
943
|
-
if (options.readPreference == null) {
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
let r = options.readPreference;
|
|
948
|
-
if (typeof r === 'string') {
|
|
949
|
-
options.readPreference = new ReadPreference(r);
|
|
950
|
-
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
951
|
-
const mode = r.mode || r.preference;
|
|
952
|
-
if (mode && typeof mode === 'string') {
|
|
953
|
-
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
954
|
-
maxStalenessSeconds: r.maxStalenessSeconds
|
|
955
|
-
});
|
|
956
|
-
}
|
|
957
|
-
} else if (!(r instanceof ReadPreference)) {
|
|
958
|
-
throw new TypeError('Invalid read preference: ' + r);
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
return options;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
942
|
function srvPollingHandler(topology) {
|
|
965
943
|
return function handleSrvPolling(ev) {
|
|
966
944
|
const previousTopologyDescription = topology.s.description;
|
package/lib/core/sessions.js
CHANGED
|
@@ -17,7 +17,8 @@ const isTransactionCommand = require('./transactions').isTransactionCommand;
|
|
|
17
17
|
const resolveClusterTime = require('./topologies/shared').resolveClusterTime;
|
|
18
18
|
const isSharded = require('./wireprotocol/shared').isSharded;
|
|
19
19
|
const maxWireVersion = require('./utils').maxWireVersion;
|
|
20
|
-
|
|
20
|
+
const now = require('./../utils').now;
|
|
21
|
+
const calculateDurationInMs = require('./../utils').calculateDurationInMs;
|
|
21
22
|
const minWireVersionForShardedTransactions = 8;
|
|
22
23
|
|
|
23
24
|
function assertAlive(session, callback) {
|
|
@@ -285,7 +286,7 @@ class ClientSession extends EventEmitter {
|
|
|
285
286
|
* @param {TransactionOptions} [options] Optional settings for the transaction
|
|
286
287
|
*/
|
|
287
288
|
withTransaction(fn, options) {
|
|
288
|
-
const startTime =
|
|
289
|
+
const startTime = now();
|
|
289
290
|
return attemptTransaction(this, startTime, fn, options);
|
|
290
291
|
}
|
|
291
292
|
}
|
|
@@ -301,7 +302,7 @@ const NON_DETERMINISTIC_WRITE_CONCERN_ERRORS = new Set([
|
|
|
301
302
|
]);
|
|
302
303
|
|
|
303
304
|
function hasNotTimedOut(startTime, max) {
|
|
304
|
-
return
|
|
305
|
+
return calculateDurationInMs(startTime) < max;
|
|
305
306
|
}
|
|
306
307
|
|
|
307
308
|
function isUnknownTransactionCommitResult(err) {
|
|
@@ -558,7 +559,7 @@ function supportsRecoveryToken(session) {
|
|
|
558
559
|
class ServerSession {
|
|
559
560
|
constructor() {
|
|
560
561
|
this.id = { id: new Binary(uuidV4(), Binary.SUBTYPE_UUID) };
|
|
561
|
-
this.lastUse =
|
|
562
|
+
this.lastUse = now();
|
|
562
563
|
this.txnNumber = 0;
|
|
563
564
|
this.isDirty = false;
|
|
564
565
|
}
|
|
@@ -573,7 +574,7 @@ class ServerSession {
|
|
|
573
574
|
// Take the difference of the lastUse timestamp and now, which will result in a value in
|
|
574
575
|
// milliseconds, and then convert milliseconds to minutes to compare to `sessionTimeoutMinutes`
|
|
575
576
|
const idleTimeMinutes = Math.round(
|
|
576
|
-
(((
|
|
577
|
+
((calculateDurationInMs(this.lastUse) % 86400000) % 3600000) / 60000
|
|
577
578
|
);
|
|
578
579
|
|
|
579
580
|
return idleTimeMinutes > sessionTimeoutMinutes - 1;
|
|
@@ -707,8 +708,13 @@ function applySession(session, command, options) {
|
|
|
707
708
|
return new MongoError('Cannot use a session that has ended');
|
|
708
709
|
}
|
|
709
710
|
|
|
711
|
+
// SPEC-1019: silently ignore explicit session with unacknowledged write for backwards compatibility
|
|
712
|
+
if (options && options.writeConcern && options.writeConcern.w === 0) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
710
716
|
const serverSession = session.serverSession;
|
|
711
|
-
serverSession.lastUse =
|
|
717
|
+
serverSession.lastUse = now();
|
|
712
718
|
command.lsid = serverSession.id;
|
|
713
719
|
|
|
714
720
|
// first apply non-transaction-specific sessions data
|
|
@@ -91,20 +91,18 @@ const VALID_MODES = [
|
|
|
91
91
|
* @return {ReadPreference}
|
|
92
92
|
*/
|
|
93
93
|
ReadPreference.fromOptions = function(options) {
|
|
94
|
+
if (!options) return null;
|
|
94
95
|
const readPreference = options.readPreference;
|
|
96
|
+
if (readPreference == null) return null;
|
|
95
97
|
const readPreferenceTags = options.readPreferenceTags;
|
|
96
|
-
|
|
97
|
-
if (readPreference == null) {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
98
|
+
const maxStalenessSeconds = options.maxStalenessSeconds;
|
|
101
99
|
if (typeof readPreference === 'string') {
|
|
102
100
|
return new ReadPreference(readPreference, readPreferenceTags);
|
|
103
101
|
} else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
|
|
104
102
|
const mode = readPreference.mode || readPreference.preference;
|
|
105
103
|
if (mode && typeof mode === 'string') {
|
|
106
104
|
return new ReadPreference(mode, readPreference.tags, {
|
|
107
|
-
maxStalenessSeconds: readPreference.maxStalenessSeconds
|
|
105
|
+
maxStalenessSeconds: readPreference.maxStalenessSeconds || maxStalenessSeconds
|
|
108
106
|
});
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -112,6 +110,60 @@ ReadPreference.fromOptions = function(options) {
|
|
|
112
110
|
return readPreference;
|
|
113
111
|
};
|
|
114
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Resolves a read preference based on well-defined inheritance rules. This method will not only
|
|
115
|
+
* determine the read preference (if there is one), but will also ensure the returned value is a
|
|
116
|
+
* properly constructed instance of `ReadPreference`.
|
|
117
|
+
*
|
|
118
|
+
* @param {Collection|Db|MongoClient} parent The parent of the operation on which to determine the read
|
|
119
|
+
* preference, used for determining the inherited read preference.
|
|
120
|
+
* @param {object} options The options passed into the method, potentially containing a read preference
|
|
121
|
+
* @returns {(ReadPreference|null)} The resolved read preference
|
|
122
|
+
*/
|
|
123
|
+
ReadPreference.resolve = function(parent, options) {
|
|
124
|
+
options = options || {};
|
|
125
|
+
const session = options.session;
|
|
126
|
+
|
|
127
|
+
const inheritedReadPreference = parent && parent.readPreference;
|
|
128
|
+
|
|
129
|
+
let readPreference;
|
|
130
|
+
if (options.readPreference) {
|
|
131
|
+
readPreference = ReadPreference.fromOptions(options);
|
|
132
|
+
} else if (session && session.inTransaction() && session.transaction.options.readPreference) {
|
|
133
|
+
// The transaction’s read preference MUST override all other user configurable read preferences.
|
|
134
|
+
readPreference = session.transaction.options.readPreference;
|
|
135
|
+
} else if (inheritedReadPreference != null) {
|
|
136
|
+
readPreference = inheritedReadPreference;
|
|
137
|
+
} else {
|
|
138
|
+
readPreference = ReadPreference.primary;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return typeof readPreference === 'string' ? new ReadPreference(readPreference) : readPreference;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Replaces options.readPreference with a ReadPreference instance
|
|
146
|
+
*/
|
|
147
|
+
ReadPreference.translate = function(options) {
|
|
148
|
+
if (options.readPreference == null) return options;
|
|
149
|
+
const r = options.readPreference;
|
|
150
|
+
|
|
151
|
+
if (typeof r === 'string') {
|
|
152
|
+
options.readPreference = new ReadPreference(r);
|
|
153
|
+
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
154
|
+
const mode = r.mode || r.preference;
|
|
155
|
+
if (mode && typeof mode === 'string') {
|
|
156
|
+
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
157
|
+
maxStalenessSeconds: r.maxStalenessSeconds
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
} else if (!(r instanceof ReadPreference)) {
|
|
161
|
+
throw new TypeError('Invalid read preference: ' + r);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return options;
|
|
165
|
+
};
|
|
166
|
+
|
|
115
167
|
/**
|
|
116
168
|
* Validate if a mode is legal
|
|
117
169
|
*
|
|
@@ -17,9 +17,10 @@ const isRetryableWritesSupported = require('./shared').isRetryableWritesSupporte
|
|
|
17
17
|
const relayEvents = require('../utils').relayEvents;
|
|
18
18
|
const isRetryableError = require('../error').isRetryableError;
|
|
19
19
|
const BSON = retrieveBSON();
|
|
20
|
-
const calculateDurationInMs = require('../utils').calculateDurationInMs;
|
|
21
20
|
const getMMAPError = require('./shared').getMMAPError;
|
|
22
21
|
const makeClientMetadata = require('../utils').makeClientMetadata;
|
|
22
|
+
const now = require('../../utils').now;
|
|
23
|
+
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
|
|
23
24
|
|
|
24
25
|
//
|
|
25
26
|
// States
|
|
@@ -426,8 +427,7 @@ var pingServer = function(self, server, cb) {
|
|
|
426
427
|
var latencyMS = new Date().getTime() - start;
|
|
427
428
|
|
|
428
429
|
// Set the last updatedTime
|
|
429
|
-
|
|
430
|
-
server.lastUpdateTime = (hrtime[0] * 1e9 + hrtime[1]) / 1e6;
|
|
430
|
+
server.lastUpdateTime = now();
|
|
431
431
|
|
|
432
432
|
// We had an error, remove it from the state
|
|
433
433
|
if (err) {
|
|
@@ -1127,7 +1127,7 @@ ReplSet.prototype.selectServer = function(selector, options, callback) {
|
|
|
1127
1127
|
}
|
|
1128
1128
|
|
|
1129
1129
|
let lastError;
|
|
1130
|
-
const start =
|
|
1130
|
+
const start = now();
|
|
1131
1131
|
const _selectServer = () => {
|
|
1132
1132
|
if (calculateDurationInMs(start) >= SERVER_SELECTION_TIMEOUT_MS) {
|
|
1133
1133
|
if (lastError != null) {
|
package/lib/core/utils.js
CHANGED
|
@@ -13,17 +13,6 @@ const uuidV4 = () => {
|
|
|
13
13
|
return result;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Returns the duration calculated from two high resolution timers in milliseconds
|
|
18
|
-
*
|
|
19
|
-
* @param {Object} started A high resolution timestamp created from `process.hrtime()`
|
|
20
|
-
* @returns {Number} The duration in milliseconds
|
|
21
|
-
*/
|
|
22
|
-
const calculateDurationInMs = started => {
|
|
23
|
-
const hrtime = process.hrtime(started);
|
|
24
|
-
return (hrtime[0] * 1e9 + hrtime[1]) / 1e6;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
16
|
/**
|
|
28
17
|
* Relays events for a given listener and emitter
|
|
29
18
|
*
|
|
@@ -83,22 +72,24 @@ function retrieveEJSON() {
|
|
|
83
72
|
* @param {(Topology|Server)} topologyOrServer
|
|
84
73
|
*/
|
|
85
74
|
function maxWireVersion(topologyOrServer) {
|
|
86
|
-
if (topologyOrServer
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
if (topologyOrServer) {
|
|
76
|
+
if (topologyOrServer.ismaster) {
|
|
77
|
+
return topologyOrServer.ismaster.maxWireVersion;
|
|
78
|
+
}
|
|
89
79
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
if (typeof topologyOrServer.lastIsMaster === 'function') {
|
|
81
|
+
const lastIsMaster = topologyOrServer.lastIsMaster();
|
|
82
|
+
if (lastIsMaster) {
|
|
83
|
+
return lastIsMaster.maxWireVersion;
|
|
84
|
+
}
|
|
94
85
|
}
|
|
95
|
-
}
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
|
|
87
|
+
if (topologyOrServer.description) {
|
|
88
|
+
return topologyOrServer.description.maxWireVersion;
|
|
89
|
+
}
|
|
99
90
|
}
|
|
100
91
|
|
|
101
|
-
return
|
|
92
|
+
return 0;
|
|
102
93
|
}
|
|
103
94
|
|
|
104
95
|
/*
|
|
@@ -259,7 +250,6 @@ const noop = () => {};
|
|
|
259
250
|
|
|
260
251
|
module.exports = {
|
|
261
252
|
uuidV4,
|
|
262
|
-
calculateDurationInMs,
|
|
263
253
|
relayEvents,
|
|
264
254
|
collationNotSupported,
|
|
265
255
|
retrieveEJSON,
|
|
@@ -66,12 +66,7 @@ function _command(server, ns, cmd, options, callback) {
|
|
|
66
66
|
finalCmd.$clusterTime = clusterTime;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
if (
|
|
70
|
-
isSharded(server) &&
|
|
71
|
-
!shouldUseOpMsg &&
|
|
72
|
-
readPreference &&
|
|
73
|
-
readPreference.preference !== 'primary'
|
|
74
|
-
) {
|
|
69
|
+
if (isSharded(server) && !shouldUseOpMsg && readPreference && readPreference.mode !== 'primary') {
|
|
75
70
|
finalCmd = {
|
|
76
71
|
$query: finalCmd,
|
|
77
72
|
$readPreference: readPreference.toJSON()
|
|
@@ -62,8 +62,13 @@ function getMore(server, ns, cursorState, batchSize, options, callback) {
|
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
const cursorId =
|
|
66
|
+
cursorState.cursorId instanceof Long
|
|
67
|
+
? cursorState.cursorId
|
|
68
|
+
: Long.fromNumber(cursorState.cursorId);
|
|
69
|
+
|
|
65
70
|
const getMoreCmd = {
|
|
66
|
-
getMore:
|
|
71
|
+
getMore: cursorId,
|
|
67
72
|
collection: collectionNamespace(ns),
|
|
68
73
|
batchSize: Math.abs(batchSize)
|
|
69
74
|
};
|
package/lib/cursor.js
CHANGED
|
@@ -832,9 +832,7 @@ class Cursor extends CoreCursor {
|
|
|
832
832
|
const fetchDocs = () => {
|
|
833
833
|
cursor._next((err, doc) => {
|
|
834
834
|
if (err) {
|
|
835
|
-
return
|
|
836
|
-
? cursor._endSession(() => handleCallback(cb, err))
|
|
837
|
-
: handleCallback(cb, err);
|
|
835
|
+
return handleCallback(cb, err);
|
|
838
836
|
}
|
|
839
837
|
|
|
840
838
|
if (doc == null) {
|
|
@@ -914,38 +912,18 @@ class Cursor extends CoreCursor {
|
|
|
914
912
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
915
913
|
options = Object.assign({}, { skipKillCursors: false }, options);
|
|
916
914
|
|
|
917
|
-
this
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
const completeClose = () => {
|
|
924
|
-
// Emit the close event for the cursor
|
|
925
|
-
this.emit('close');
|
|
926
|
-
|
|
927
|
-
// Callback if provided
|
|
928
|
-
if (typeof callback === 'function') {
|
|
929
|
-
return handleCallback(callback, null, this);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
// Return a Promise
|
|
933
|
-
return new this.s.promiseLibrary(resolve => {
|
|
934
|
-
resolve();
|
|
935
|
-
});
|
|
936
|
-
};
|
|
937
|
-
|
|
938
|
-
if (this.cursorState.session) {
|
|
939
|
-
if (typeof callback === 'function') {
|
|
940
|
-
return this._endSession(() => completeClose());
|
|
915
|
+
return maybePromise(this, callback, cb => {
|
|
916
|
+
this.s.state = CursorState.CLOSED;
|
|
917
|
+
if (!options.skipKillCursors) {
|
|
918
|
+
// Kill the cursor
|
|
919
|
+
this.kill();
|
|
941
920
|
}
|
|
942
921
|
|
|
943
|
-
|
|
944
|
-
this.
|
|
922
|
+
this._endSession(() => {
|
|
923
|
+
this.emit('close');
|
|
924
|
+
cb(null, this);
|
|
945
925
|
});
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
return completeClose();
|
|
926
|
+
});
|
|
949
927
|
}
|
|
950
928
|
|
|
951
929
|
/**
|
package/lib/db.js
CHANGED
|
@@ -14,7 +14,6 @@ const Logger = require('./core').Logger;
|
|
|
14
14
|
const Collection = require('./collection');
|
|
15
15
|
const mergeOptionsAndWriteConcern = require('./utils').mergeOptionsAndWriteConcern;
|
|
16
16
|
const executeLegacyOperation = require('./utils').executeLegacyOperation;
|
|
17
|
-
const resolveReadPreference = require('./utils').resolveReadPreference;
|
|
18
17
|
const ChangeStream = require('./change_stream');
|
|
19
18
|
const deprecate = require('util').deprecate;
|
|
20
19
|
const deprecateOptions = require('./utils').deprecateOptions;
|
|
@@ -35,6 +34,7 @@ const AggregateOperation = require('./operations/aggregate');
|
|
|
35
34
|
const AddUserOperation = require('./operations/add_user');
|
|
36
35
|
const CollectionsOperation = require('./operations/collections');
|
|
37
36
|
const CommandOperation = require('./operations/command');
|
|
37
|
+
const RunCommandOperation = require('./operations/run_command');
|
|
38
38
|
const CreateCollectionOperation = require('./operations/create_collection');
|
|
39
39
|
const CreateIndexOperation = require('./operations/create_index');
|
|
40
40
|
const DropCollectionOperation = require('./operations/drop').DropCollectionOperation;
|
|
@@ -290,7 +290,7 @@ Db.prototype.command = function(command, options, callback) {
|
|
|
290
290
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
291
291
|
options = Object.assign({}, options);
|
|
292
292
|
|
|
293
|
-
const commandOperation = new
|
|
293
|
+
const commandOperation = new RunCommandOperation(this, command, options);
|
|
294
294
|
|
|
295
295
|
return executeOperation(this.s.topology, commandOperation, callback);
|
|
296
296
|
};
|
|
@@ -709,7 +709,7 @@ Db.prototype.collections = function(options, callback) {
|
|
|
709
709
|
Db.prototype.executeDbAdminCommand = function(selector, options, callback) {
|
|
710
710
|
if (typeof options === 'function') (callback = options), (options = {});
|
|
711
711
|
options = options || {};
|
|
712
|
-
options.readPreference =
|
|
712
|
+
options.readPreference = ReadPreference.resolve(this, options);
|
|
713
713
|
|
|
714
714
|
const executeDbAdminCommandOperation = new ExecuteDbAdminCommandOperation(
|
|
715
715
|
this,
|
package/lib/error.js
CHANGED
|
@@ -1,45 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const MongoNetworkError = require('./core').MongoNetworkError;
|
|
4
|
-
const mongoErrorContextSymbol = require('./core').mongoErrorContextSymbol;
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
// From spec@https://github.com/mongodb/specifications/blob/f93d78191f3db2898a59013a7ed5650352ef6da8/source/change-streams/change-streams.rst#resumable-error
|
|
6
|
+
const GET_MORE_RESUMABLE_CODES = new Set([
|
|
7
|
+
6, // HostUnreachable
|
|
8
|
+
7, // HostNotFound
|
|
9
|
+
89, // NetworkTimeout
|
|
10
|
+
91, // ShutdownInProgress
|
|
11
|
+
189, // PrimarySteppedDown
|
|
12
|
+
262, // ExceededTimeLimit
|
|
13
|
+
9001, // SocketException
|
|
14
|
+
10107, // NotMaster
|
|
15
|
+
11600, // InterruptedAtShutdown
|
|
16
|
+
11602, // InterruptedDueToReplStateChange
|
|
17
|
+
13435, // NotMasterNoSlaveOk
|
|
18
|
+
13436, // NotMasterOrSecondary
|
|
19
|
+
63, // StaleShardVersion
|
|
20
|
+
150, // StaleEpoch
|
|
21
|
+
13388, // StaleConfig
|
|
22
|
+
234, // RetryChangeStream
|
|
23
|
+
133 // FailedToSatisfyReadPreference
|
|
10
24
|
]);
|
|
11
25
|
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
// An error is considered resumable if it meets any of the following criteria:
|
|
15
|
-
// - any error encountered which is not a server error (e.g. a timeout error or network error)
|
|
16
|
-
// - any server error response from a getMore command excluding those containing the error label
|
|
17
|
-
// NonRetryableChangeStreamError and those containing the following error codes:
|
|
18
|
-
// - Interrupted: 11601
|
|
19
|
-
// - CappedPositionLost: 136
|
|
20
|
-
// - CursorKilled: 237
|
|
21
|
-
//
|
|
22
|
-
// An error on an aggregate command is not a resumable error. Only errors on a getMore command may be considered resumable errors.
|
|
23
|
-
|
|
24
|
-
function isGetMoreError(error) {
|
|
25
|
-
if (error[mongoErrorContextSymbol]) {
|
|
26
|
-
return error[mongoErrorContextSymbol].isGetMore;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function isResumableError(error) {
|
|
31
|
-
if (!isGetMoreError(error)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
|
|
26
|
+
function isResumableError(error, wireVersion) {
|
|
35
27
|
if (error instanceof MongoNetworkError) {
|
|
36
28
|
return true;
|
|
37
29
|
}
|
|
38
30
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
31
|
+
if (wireVersion >= 9) {
|
|
32
|
+
return error.hasErrorLabel('ResumableChangeStreamError');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return GET_MORE_RESUMABLE_CODES.has(error.code);
|
|
43
36
|
}
|
|
44
37
|
|
|
45
|
-
module.exports = {
|
|
38
|
+
module.exports = { GET_MORE_RESUMABLE_CODES, isResumableError };
|
package/lib/mongo_client.js
CHANGED
|
@@ -146,6 +146,10 @@ const validOptions = require('./operations/connect').validOptions;
|
|
|
146
146
|
* @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
|
|
147
147
|
* @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
|
|
148
148
|
* @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
|
|
149
|
+
* @param {number} [options.maxPoolSize=10] **Only applies to the unified topology** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
|
|
150
|
+
* @param {number} [options.minPoolSize=0] **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
|
|
151
|
+
* @param {number} [options.maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
|
|
152
|
+
* @param {number} [options.waitQueueTimeoutMS=0] **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
|
|
149
153
|
* @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
|
|
150
154
|
* @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
|
|
151
155
|
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
@@ -415,6 +419,10 @@ MongoClient.prototype.isConnected = function(options) {
|
|
|
415
419
|
* @param {Number} [options.localThresholdMS=15] **Only applies to the unified topology** The size of the latency window for selecting among multiple suitable servers
|
|
416
420
|
* @param {Number} [options.serverSelectionTimeoutMS=30000] **Only applies to the unified topology** How long to block for server selection before throwing an error
|
|
417
421
|
* @param {Number} [options.heartbeatFrequencyMS=10000] **Only applies to the unified topology** The frequency with which topology updates are scheduled
|
|
422
|
+
* @param {number} [options.maxPoolSize=10] **Only applies to the unified topology** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
|
|
423
|
+
* @param {number} [options.minPoolSize=0] **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
|
|
424
|
+
* @param {number} [options.maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
|
|
425
|
+
* @param {number} [options.waitQueueTimeoutMS=0] **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
|
|
418
426
|
* @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
|
|
419
427
|
* @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
|
|
420
428
|
* @param {MongoClient~connectCallback} [callback] The command result callback
|
|
@@ -8,7 +8,6 @@ const decorateWithReadConcern = require('../utils').decorateWithReadConcern;
|
|
|
8
8
|
const ensureIndexDb = require('./db_ops').ensureIndex;
|
|
9
9
|
const evaluate = require('./db_ops').evaluate;
|
|
10
10
|
const executeCommand = require('./db_ops').executeCommand;
|
|
11
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
12
11
|
const handleCallback = require('../utils').handleCallback;
|
|
13
12
|
const indexInformationDb = require('./db_ops').indexInformation;
|
|
14
13
|
const Long = require('../core').BSON.Long;
|
|
@@ -188,7 +187,7 @@ function group(coll, keys, condition, initial, reduce, finalize, command, option
|
|
|
188
187
|
|
|
189
188
|
options = Object.assign({}, options);
|
|
190
189
|
// Ensure we have the right read preference inheritance
|
|
191
|
-
options.readPreference =
|
|
190
|
+
options.readPreference = ReadPreference.resolve(coll, options);
|
|
192
191
|
|
|
193
192
|
// Do we have a readConcern specified
|
|
194
193
|
decorateWithReadConcern(selector, coll, options);
|
|
@@ -7,7 +7,6 @@ const debugOptions = require('../utils').debugOptions;
|
|
|
7
7
|
const handleCallback = require('../utils').handleCallback;
|
|
8
8
|
const MongoError = require('../core').MongoError;
|
|
9
9
|
const ReadPreference = require('../core').ReadPreference;
|
|
10
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
11
10
|
const MongoDBNamespace = require('../utils').MongoDBNamespace;
|
|
12
11
|
|
|
13
12
|
const debugFields = [
|
|
@@ -38,9 +37,9 @@ class CommandOperation extends OperationBase {
|
|
|
38
37
|
|
|
39
38
|
if (!this.hasAspect(Aspect.WRITE_OPERATION)) {
|
|
40
39
|
if (collection != null) {
|
|
41
|
-
this.options.readPreference =
|
|
40
|
+
this.options.readPreference = ReadPreference.resolve(collection, options);
|
|
42
41
|
} else {
|
|
43
|
-
this.options.readPreference =
|
|
42
|
+
this.options.readPreference = ReadPreference.resolve(db, options);
|
|
44
43
|
}
|
|
45
44
|
} else {
|
|
46
45
|
if (collection != null) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const Aspect = require('./operation').Aspect;
|
|
4
4
|
const OperationBase = require('./operation').OperationBase;
|
|
5
|
-
const
|
|
5
|
+
const ReadPreference = require('../core').ReadPreference;
|
|
6
6
|
const ReadConcern = require('../read_concern');
|
|
7
7
|
const WriteConcern = require('../write_concern');
|
|
8
8
|
const maxWireVersion = require('../core/utils').maxWireVersion;
|
|
@@ -16,9 +16,10 @@ class CommandOperationV2 extends OperationBase {
|
|
|
16
16
|
super(options);
|
|
17
17
|
|
|
18
18
|
this.ns = parent.s.namespace.withCollection('$cmd');
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
19
|
+
const propertyProvider = this.hasAspect(Aspect.NO_INHERIT_OPTIONS) ? undefined : parent;
|
|
20
|
+
this.readPreference = ReadPreference.resolve(propertyProvider, this.options);
|
|
21
|
+
this.readConcern = resolveReadConcern(propertyProvider, this.options);
|
|
22
|
+
this.writeConcern = resolveWriteConcern(propertyProvider, this.options);
|
|
22
23
|
this.explain = false;
|
|
23
24
|
|
|
24
25
|
if (operationOptions && typeof operationOptions.fullResponse === 'boolean') {
|
|
@@ -97,11 +98,11 @@ class CommandOperationV2 extends OperationBase {
|
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
function resolveWriteConcern(parent, options) {
|
|
100
|
-
return WriteConcern.fromOptions(options) || parent.writeConcern;
|
|
101
|
+
return WriteConcern.fromOptions(options) || (parent && parent.writeConcern);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
function resolveReadConcern(parent, options) {
|
|
104
|
-
return ReadConcern.fromOptions(options) || parent.readConcern;
|
|
105
|
+
return ReadConcern.fromOptions(options) || (parent && parent.readConcern);
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
module.exports = CommandOperationV2;
|
|
@@ -151,6 +151,11 @@ const validOptionNames = [
|
|
|
151
151
|
'tlsCertificateKeyFilePassword',
|
|
152
152
|
'minHeartbeatFrequencyMS',
|
|
153
153
|
'heartbeatFrequencyMS',
|
|
154
|
+
|
|
155
|
+
// CMAP options
|
|
156
|
+
'maxPoolSize',
|
|
157
|
+
'minPoolSize',
|
|
158
|
+
'maxIdleTimeMS',
|
|
154
159
|
'waitQueueTimeoutMS'
|
|
155
160
|
];
|
|
156
161
|
|
|
@@ -290,6 +295,12 @@ function connect(mongoClient, url, options, callback) {
|
|
|
290
295
|
delete _finalOptions.db_options.auth;
|
|
291
296
|
}
|
|
292
297
|
|
|
298
|
+
// `journal` should be translated to `j` for the driver
|
|
299
|
+
if (_finalOptions.journal != null) {
|
|
300
|
+
_finalOptions.j = _finalOptions.journal;
|
|
301
|
+
_finalOptions.journal = undefined;
|
|
302
|
+
}
|
|
303
|
+
|
|
293
304
|
// resolve tls options if needed
|
|
294
305
|
resolveTLSOptions(_finalOptions);
|
|
295
306
|
|
|
@@ -134,10 +134,9 @@ function toArray(cursor, callback) {
|
|
|
134
134
|
const fetchDocs = () => {
|
|
135
135
|
cursor._next((err, doc) => {
|
|
136
136
|
if (err) {
|
|
137
|
-
return
|
|
138
|
-
? cursor._endSession(() => handleCallback(callback, err))
|
|
139
|
-
: handleCallback(callback, err);
|
|
137
|
+
return handleCallback(callback, err);
|
|
140
138
|
}
|
|
139
|
+
|
|
141
140
|
if (doc == null) {
|
|
142
141
|
return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, items));
|
|
143
142
|
}
|
package/lib/operations/db_ops.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const applyWriteConcern = require('../utils').applyWriteConcern;
|
|
4
4
|
const Code = require('../core').BSON.Code;
|
|
5
|
-
const resolveReadPreference = require('../utils').resolveReadPreference;
|
|
6
5
|
const debugOptions = require('../utils').debugOptions;
|
|
7
6
|
const handleCallback = require('../utils').handleCallback;
|
|
8
7
|
const MongoError = require('../core').MongoError;
|
|
@@ -225,7 +224,7 @@ function executeCommand(db, command, options, callback) {
|
|
|
225
224
|
const dbName = options.dbName || options.authdb || db.databaseName;
|
|
226
225
|
|
|
227
226
|
// Convert the readPreference if its not a write
|
|
228
|
-
options.readPreference =
|
|
227
|
+
options.readPreference = ReadPreference.resolve(db, options);
|
|
229
228
|
|
|
230
229
|
// Debug information
|
|
231
230
|
if (db.s.logger.isDebug())
|