mongodb 4.7.0 → 4.9.0
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/bson.js +4 -2
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +1 -0
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +136 -271
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +2 -32
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +1 -153
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +3 -6
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +21 -84
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +196 -170
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +2 -6
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +1 -3
- package/lib/cmap/wire_protocol/constants.js.map +1 -1
- package/lib/collection.js +24 -9
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +62 -75
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +115 -0
- package/lib/cursor/change_stream_cursor.js.map +1 -0
- package/lib/cursor/list_collections_cursor.js +37 -0
- package/lib/cursor/list_collections_cursor.js.map +1 -0
- package/lib/cursor/list_indexes_cursor.js +36 -0
- package/lib/cursor/list_indexes_cursor.js.map +1 -0
- package/lib/db.js +2 -2
- package/lib/db.js.map +1 -1
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js +3 -13
- package/lib/encrypter.js.map +1 -1
- package/lib/index.js +28 -21
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +62 -21
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/distinct.js +5 -5
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/estimated_document_count.js +5 -0
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/execute_operation.js +17 -8
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +3 -0
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/get_more.js +32 -7
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +39 -65
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/kill_cursors.js +32 -0
- package/lib/operations/kill_cursors.js.map +1 -0
- package/lib/operations/list_collections.js +1 -33
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/operation.js +4 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/read_preference.js.map +1 -1
- package/lib/sdam/common.js +2 -1
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/monitor.js +2 -1
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +1 -52
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +51 -58
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/srv_polling.js +2 -2
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +28 -67
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +24 -42
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +29 -31
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +65 -70
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +136 -73
- package/package.json +23 -22
- package/src/bson.ts +4 -0
- package/src/bulk/common.ts +1 -0
- package/src/change_stream.ts +147 -373
- package/src/cmap/command_monitoring_events.ts +3 -37
- package/src/cmap/commands.ts +2 -190
- package/src/cmap/connect.ts +20 -25
- package/src/cmap/connection.ts +27 -139
- package/src/cmap/connection_pool.ts +208 -169
- package/src/cmap/message_stream.ts +2 -3
- package/src/cmap/wire_protocol/compression.ts +8 -6
- package/src/cmap/wire_protocol/constants.ts +0 -2
- package/src/collection.ts +27 -13
- package/src/connection_string.ts +1 -1
- package/src/cursor/abstract_cursor.ts +98 -87
- package/src/cursor/change_stream_cursor.ts +194 -0
- package/src/cursor/list_collections_cursor.ts +52 -0
- package/src/cursor/list_indexes_cursor.ts +41 -0
- package/src/db.ts +2 -5
- package/src/deps.ts +13 -22
- package/src/encrypter.ts +4 -14
- package/src/index.ts +13 -9
- package/src/mongo_client.ts +102 -33
- package/src/mongo_types.ts +81 -57
- package/src/operations/common_functions.ts +1 -1
- package/src/operations/create_collection.ts +1 -2
- package/src/operations/distinct.ts +7 -9
- package/src/operations/estimated_document_count.ts +6 -0
- package/src/operations/execute_operation.ts +17 -8
- package/src/operations/find.ts +9 -0
- package/src/operations/get_more.ts +56 -13
- package/src/operations/indexes.ts +52 -89
- package/src/operations/kill_cursors.ts +53 -0
- package/src/operations/list_collections.ts +0 -43
- package/src/operations/operation.ts +5 -1
- package/src/read_preference.ts +5 -9
- package/src/sdam/common.ts +2 -0
- package/src/sdam/monitor.ts +2 -1
- package/src/sdam/server.ts +4 -89
- package/src/sdam/server_description.ts +70 -80
- package/src/sdam/srv_polling.ts +1 -1
- package/src/sdam/topology.ts +37 -103
- package/src/sdam/topology_description.ts +44 -68
- package/src/sessions.ts +32 -39
- package/src/utils.ts +78 -75
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Long } from '../bson';
|
|
2
|
+
import { MongoRuntimeError } from '../error';
|
|
3
|
+
import type { Server } from '../sdam/server';
|
|
4
|
+
import type { ClientSession } from '../sessions';
|
|
5
|
+
import type { Callback, MongoDBNamespace } from '../utils';
|
|
6
|
+
import { AbstractOperation, Aspect, defineAspects, OperationOptions } from './operation';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* https://www.mongodb.com/docs/manual/reference/command/killCursors/
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
interface KillCursorsCommand {
|
|
13
|
+
killCursors: string;
|
|
14
|
+
cursors: Long[];
|
|
15
|
+
comment?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class KillCursorsOperation extends AbstractOperation {
|
|
19
|
+
cursorId: Long;
|
|
20
|
+
|
|
21
|
+
constructor(cursorId: Long, ns: MongoDBNamespace, server: Server, options: OperationOptions) {
|
|
22
|
+
super(options);
|
|
23
|
+
this.ns = ns;
|
|
24
|
+
this.cursorId = cursorId;
|
|
25
|
+
this.server = server;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
execute(server: Server, session: ClientSession | undefined, callback: Callback<void>): void {
|
|
29
|
+
if (server !== this.server) {
|
|
30
|
+
return callback(
|
|
31
|
+
new MongoRuntimeError('Killcursor must run on the same server operation began on')
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const killCursors = this.ns.collection;
|
|
36
|
+
if (killCursors == null) {
|
|
37
|
+
// Cursors should have adopted the namespace returned by MongoDB
|
|
38
|
+
// which should always defined a collection name (even a pseudo one, ex. db.aggregate())
|
|
39
|
+
return callback(
|
|
40
|
+
new MongoRuntimeError('A collection name must be determined before killCursors')
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const killCursorsCommand: KillCursorsCommand = {
|
|
45
|
+
killCursors,
|
|
46
|
+
cursors: [this.cursorId]
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
server.command(this.ns, killCursorsCommand, { session }, () => callback());
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
defineAspects(KillCursorsOperation, [Aspect.MUST_SELECT_SAME_SERVER]);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Binary, Document } from '../bson';
|
|
2
|
-
import { AbstractCursor } from '../cursor/abstract_cursor';
|
|
3
2
|
import type { Db } from '../db';
|
|
4
3
|
import type { Server } from '../sdam/server';
|
|
5
4
|
import type { ClientSession } from '../sessions';
|
|
6
5
|
import { Callback, maxWireVersion } from '../utils';
|
|
7
6
|
import { CommandOperation, CommandOperationOptions } from './command';
|
|
8
|
-
import { executeOperation, ExecutionResult } from './execute_operation';
|
|
9
7
|
import { Aspect, defineAspects } from './operation';
|
|
10
8
|
|
|
11
9
|
/** @public */
|
|
@@ -86,47 +84,6 @@ export interface CollectionInfo extends Document {
|
|
|
86
84
|
idIndex?: Document;
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
/** @public */
|
|
90
|
-
export class ListCollectionsCursor<
|
|
91
|
-
T extends Pick<CollectionInfo, 'name' | 'type'> | CollectionInfo =
|
|
92
|
-
| Pick<CollectionInfo, 'name' | 'type'>
|
|
93
|
-
| CollectionInfo
|
|
94
|
-
> extends AbstractCursor<T> {
|
|
95
|
-
parent: Db;
|
|
96
|
-
filter: Document;
|
|
97
|
-
options?: ListCollectionsOptions;
|
|
98
|
-
|
|
99
|
-
constructor(db: Db, filter: Document, options?: ListCollectionsOptions) {
|
|
100
|
-
super(db.s.client, db.s.namespace, options);
|
|
101
|
-
this.parent = db;
|
|
102
|
-
this.filter = filter;
|
|
103
|
-
this.options = options;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
clone(): ListCollectionsCursor<T> {
|
|
107
|
-
return new ListCollectionsCursor(this.parent, this.filter, {
|
|
108
|
-
...this.options,
|
|
109
|
-
...this.cursorOptions
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** @internal */
|
|
114
|
-
_initialize(session: ClientSession | undefined, callback: Callback<ExecutionResult>): void {
|
|
115
|
-
const operation = new ListCollectionsOperation(this.parent, this.filter, {
|
|
116
|
-
...this.cursorOptions,
|
|
117
|
-
...this.options,
|
|
118
|
-
session
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
executeOperation(this.parent.s.client, operation, (err, response) => {
|
|
122
|
-
if (err || response == null) return callback(err);
|
|
123
|
-
|
|
124
|
-
// TODO: NODE-2882
|
|
125
|
-
callback(undefined, { server: operation.server, session, response });
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
87
|
defineAspects(ListCollectionsOperation, [
|
|
131
88
|
Aspect.READ_OPERATION,
|
|
132
89
|
Aspect.RETRYABLE,
|
|
@@ -11,7 +11,7 @@ export const Aspect = {
|
|
|
11
11
|
EXPLAINABLE: Symbol('EXPLAINABLE'),
|
|
12
12
|
SKIP_COLLATION: Symbol('SKIP_COLLATION'),
|
|
13
13
|
CURSOR_CREATING: Symbol('CURSOR_CREATING'),
|
|
14
|
-
|
|
14
|
+
MUST_SELECT_SAME_SERVER: Symbol('MUST_SELECT_SAME_SERVER')
|
|
15
15
|
} as const;
|
|
16
16
|
|
|
17
17
|
/** @public */
|
|
@@ -94,6 +94,10 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
94
94
|
return this[kSession];
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
clearSession() {
|
|
98
|
+
this[kSession] = undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
97
101
|
get canRetryRead(): boolean {
|
|
98
102
|
return true;
|
|
99
103
|
}
|
package/src/read_preference.ts
CHANGED
|
@@ -163,14 +163,10 @@ export class ReadPreference {
|
|
|
163
163
|
} else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
|
|
164
164
|
const mode = readPreference.mode || readPreference.preference;
|
|
165
165
|
if (mode && typeof mode === 'string') {
|
|
166
|
-
return new ReadPreference(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
maxStalenessSeconds: readPreference.maxStalenessSeconds,
|
|
171
|
-
hedge: options.hedge
|
|
172
|
-
}
|
|
173
|
-
);
|
|
166
|
+
return new ReadPreference(mode, readPreference.tags ?? readPreferenceTags, {
|
|
167
|
+
maxStalenessSeconds: readPreference.maxStalenessSeconds,
|
|
168
|
+
hedge: options.hedge
|
|
169
|
+
});
|
|
174
170
|
}
|
|
175
171
|
}
|
|
176
172
|
|
|
@@ -193,7 +189,7 @@ export class ReadPreference {
|
|
|
193
189
|
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
194
190
|
const mode = r.mode || r.preference;
|
|
195
191
|
if (mode && typeof mode === 'string') {
|
|
196
|
-
options.readPreference = new ReadPreference(mode
|
|
192
|
+
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
197
193
|
maxStalenessSeconds: r.maxStalenessSeconds
|
|
198
194
|
});
|
|
199
195
|
}
|
package/src/sdam/common.ts
CHANGED
package/src/sdam/monitor.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setTimeout } from 'timers';
|
|
1
|
+
import { clearTimeout, setTimeout } from 'timers';
|
|
2
2
|
|
|
3
3
|
import { Document, Long } from '../bson';
|
|
4
4
|
import { connect } from '../cmap/connect';
|
|
@@ -374,6 +374,7 @@ function makeTopologyVersion(tv: TopologyVersion) {
|
|
|
374
374
|
return {
|
|
375
375
|
processId: tv.processId,
|
|
376
376
|
// tests mock counter as just number, but in a real situation counter should always be a Long
|
|
377
|
+
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
377
378
|
counter: Long.isLong(tv.counter) ? tv.counter : Long.fromNumber(tv.counter)
|
|
378
379
|
};
|
|
379
380
|
}
|
package/src/sdam/server.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Document
|
|
1
|
+
import type { Document } from '../bson';
|
|
2
2
|
import { CommandOptions, Connection, DestroyOptions, GetMoreOptions } from '../cmap/connection';
|
|
3
3
|
import {
|
|
4
4
|
ConnectionPool,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
MongoNetworkError,
|
|
30
30
|
MongoNetworkTimeoutError,
|
|
31
31
|
MongoServerClosedError,
|
|
32
|
+
MongoServerError,
|
|
32
33
|
MongoUnexpectedServerResponseError,
|
|
33
34
|
needsRetryableWriteLabel
|
|
34
35
|
} from '../error';
|
|
@@ -374,88 +375,6 @@ export class Server extends TypedEventEmitter<ServerEvents> {
|
|
|
374
375
|
callback
|
|
375
376
|
);
|
|
376
377
|
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Execute a `getMore` against the server
|
|
380
|
-
* @internal
|
|
381
|
-
*/
|
|
382
|
-
getMore(
|
|
383
|
-
ns: MongoDBNamespace,
|
|
384
|
-
cursorId: Long,
|
|
385
|
-
options: GetMoreOptions,
|
|
386
|
-
callback: Callback<Document>
|
|
387
|
-
): void {
|
|
388
|
-
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
|
|
389
|
-
callback(new MongoServerClosedError());
|
|
390
|
-
return;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
this.s.operationCount += 1;
|
|
394
|
-
|
|
395
|
-
this.s.pool.withConnection(
|
|
396
|
-
options.session?.pinnedConnection,
|
|
397
|
-
(err, conn, cb) => {
|
|
398
|
-
if (err || !conn) {
|
|
399
|
-
this.s.operationCount -= 1;
|
|
400
|
-
markServerUnknown(this, err);
|
|
401
|
-
return cb(err);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
conn.getMore(
|
|
405
|
-
ns,
|
|
406
|
-
cursorId,
|
|
407
|
-
options,
|
|
408
|
-
makeOperationHandler(this, conn, {}, options, (error, response) => {
|
|
409
|
-
this.s.operationCount -= 1;
|
|
410
|
-
cb(error, response);
|
|
411
|
-
})
|
|
412
|
-
);
|
|
413
|
-
},
|
|
414
|
-
callback
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Execute a `killCursors` command against the server
|
|
420
|
-
* @internal
|
|
421
|
-
*/
|
|
422
|
-
killCursors(
|
|
423
|
-
ns: MongoDBNamespace,
|
|
424
|
-
cursorIds: Long[],
|
|
425
|
-
options: CommandOptions,
|
|
426
|
-
callback?: Callback
|
|
427
|
-
): void {
|
|
428
|
-
if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
|
|
429
|
-
if (typeof callback === 'function') {
|
|
430
|
-
callback(new MongoServerClosedError());
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
this.s.operationCount += 1;
|
|
437
|
-
this.s.pool.withConnection(
|
|
438
|
-
options.session?.pinnedConnection,
|
|
439
|
-
(err, conn, cb) => {
|
|
440
|
-
if (err || !conn) {
|
|
441
|
-
this.s.operationCount -= 1;
|
|
442
|
-
markServerUnknown(this, err);
|
|
443
|
-
return cb(err);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
conn.killCursors(
|
|
447
|
-
ns,
|
|
448
|
-
cursorIds,
|
|
449
|
-
options,
|
|
450
|
-
makeOperationHandler(this, conn, {}, undefined, (error, response) => {
|
|
451
|
-
this.s.operationCount -= 1;
|
|
452
|
-
cb(error, response);
|
|
453
|
-
})
|
|
454
|
-
);
|
|
455
|
-
},
|
|
456
|
-
callback
|
|
457
|
-
);
|
|
458
|
-
}
|
|
459
378
|
}
|
|
460
379
|
|
|
461
380
|
function calculateRoundTripTime(oldRtt: number, duration: number): number {
|
|
@@ -467,7 +386,7 @@ function calculateRoundTripTime(oldRtt: number, duration: number): number {
|
|
|
467
386
|
return alpha * duration + (1 - alpha) * oldRtt;
|
|
468
387
|
}
|
|
469
388
|
|
|
470
|
-
function markServerUnknown(server: Server, error?:
|
|
389
|
+
function markServerUnknown(server: Server, error?: MongoServerError) {
|
|
471
390
|
// Load balancer servers can never be marked unknown.
|
|
472
391
|
if (server.loadBalanced) {
|
|
473
392
|
return;
|
|
@@ -479,11 +398,7 @@ function markServerUnknown(server: Server, error?: MongoError) {
|
|
|
479
398
|
|
|
480
399
|
server.emit(
|
|
481
400
|
Server.DESCRIPTION_RECEIVED,
|
|
482
|
-
new ServerDescription(server.description.hostAddress, undefined, {
|
|
483
|
-
error,
|
|
484
|
-
topologyVersion:
|
|
485
|
-
error && error.topologyVersion ? error.topologyVersion : server.description.topologyVersion
|
|
486
|
-
})
|
|
401
|
+
new ServerDescription(server.description.hostAddress, undefined, { error })
|
|
487
402
|
);
|
|
488
403
|
}
|
|
489
404
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Document, Long, ObjectId } from '../bson';
|
|
2
|
-
import
|
|
3
|
-
import { arrayStrictEqual, errorStrictEqual, HostAddress, now } from '../utils';
|
|
2
|
+
import { MongoRuntimeError, MongoServerError } from '../error';
|
|
3
|
+
import { arrayStrictEqual, compareObjectId, errorStrictEqual, HostAddress, now } from '../utils';
|
|
4
4
|
import type { ClusterTime } from './common';
|
|
5
5
|
import { ServerType } from './common';
|
|
6
6
|
|
|
@@ -31,14 +31,11 @@ export type TagSet = { [key: string]: string };
|
|
|
31
31
|
/** @internal */
|
|
32
32
|
export interface ServerDescriptionOptions {
|
|
33
33
|
/** An Error used for better reporting debugging */
|
|
34
|
-
error?:
|
|
34
|
+
error?: MongoServerError;
|
|
35
35
|
|
|
36
36
|
/** The round trip time to ping this server (in ms) */
|
|
37
37
|
roundTripTime?: number;
|
|
38
38
|
|
|
39
|
-
/** The topologyVersion */
|
|
40
|
-
topologyVersion?: TopologyVersion;
|
|
41
|
-
|
|
42
39
|
/** If the client is in load balancing mode. */
|
|
43
40
|
loadBalanced?: boolean;
|
|
44
41
|
}
|
|
@@ -50,28 +47,25 @@ export interface ServerDescriptionOptions {
|
|
|
50
47
|
* @public
|
|
51
48
|
*/
|
|
52
49
|
export class ServerDescription {
|
|
53
|
-
private _hostAddress: HostAddress;
|
|
54
50
|
address: string;
|
|
55
51
|
type: ServerType;
|
|
56
52
|
hosts: string[];
|
|
57
53
|
passives: string[];
|
|
58
54
|
arbiters: string[];
|
|
59
55
|
tags: TagSet;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
topologyVersion?: TopologyVersion;
|
|
56
|
+
error: MongoServerError | null;
|
|
57
|
+
topologyVersion: TopologyVersion | null;
|
|
63
58
|
minWireVersion: number;
|
|
64
59
|
maxWireVersion: number;
|
|
65
60
|
roundTripTime: number;
|
|
66
61
|
lastUpdateTime: number;
|
|
67
62
|
lastWriteDate: number;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
logicalSessionTimeoutMinutes?: number;
|
|
63
|
+
me: string | null;
|
|
64
|
+
primary: string | null;
|
|
65
|
+
setName: string | null;
|
|
66
|
+
setVersion: number | null;
|
|
67
|
+
electionId: ObjectId | null;
|
|
68
|
+
logicalSessionTimeoutMinutes: number | null;
|
|
75
69
|
|
|
76
70
|
// NOTE: does this belong here? It seems we should gossip the cluster time at the CMAP level
|
|
77
71
|
$clusterTime?: ClusterTime;
|
|
@@ -83,14 +77,19 @@ export class ServerDescription {
|
|
|
83
77
|
* @param address - The address of the server
|
|
84
78
|
* @param hello - An optional hello response for this server
|
|
85
79
|
*/
|
|
86
|
-
constructor(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
80
|
+
constructor(
|
|
81
|
+
address: HostAddress | string,
|
|
82
|
+
hello?: Document,
|
|
83
|
+
options: ServerDescriptionOptions = {}
|
|
84
|
+
) {
|
|
85
|
+
if (address == null || address === '') {
|
|
86
|
+
throw new MongoRuntimeError('ServerDescription must be provided with a non-empty address');
|
|
93
87
|
}
|
|
88
|
+
|
|
89
|
+
this.address =
|
|
90
|
+
typeof address === 'string'
|
|
91
|
+
? HostAddress.fromString(address).toString(false) // Use HostAddress to normalize
|
|
92
|
+
: address.toString(false);
|
|
94
93
|
this.type = parseServerType(hello, options);
|
|
95
94
|
this.hosts = hello?.hosts?.map((host: string) => host.toLowerCase()) ?? [];
|
|
96
95
|
this.passives = hello?.passives?.map((host: string) => host.toLowerCase()) ?? [];
|
|
@@ -101,49 +100,20 @@ export class ServerDescription {
|
|
|
101
100
|
this.roundTripTime = options?.roundTripTime ?? -1;
|
|
102
101
|
this.lastUpdateTime = now();
|
|
103
102
|
this.lastWriteDate = hello?.lastWrite?.lastWriteDate ?? 0;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (hello?.primary) {
|
|
116
|
-
this.primary = hello.primary;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (hello?.me) {
|
|
120
|
-
this.me = hello.me.toLowerCase();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (hello?.setName) {
|
|
124
|
-
this.setName = hello.setName;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (hello?.setVersion) {
|
|
128
|
-
this.setVersion = hello.setVersion;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (hello?.electionId) {
|
|
132
|
-
this.electionId = hello.electionId;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (hello?.logicalSessionTimeoutMinutes) {
|
|
136
|
-
this.logicalSessionTimeoutMinutes = hello.logicalSessionTimeoutMinutes;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (hello?.$clusterTime) {
|
|
140
|
-
this.$clusterTime = hello.$clusterTime;
|
|
141
|
-
}
|
|
103
|
+
this.error = options.error ?? null;
|
|
104
|
+
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
105
|
+
this.topologyVersion = this.error?.topologyVersion ?? hello?.topologyVersion ?? null;
|
|
106
|
+
this.setName = hello?.setName ?? null;
|
|
107
|
+
this.setVersion = hello?.setVersion ?? null;
|
|
108
|
+
this.electionId = hello?.electionId ?? null;
|
|
109
|
+
this.logicalSessionTimeoutMinutes = hello?.logicalSessionTimeoutMinutes ?? null;
|
|
110
|
+
this.primary = hello?.primary ?? null;
|
|
111
|
+
this.me = hello?.me?.toLowerCase() ?? null;
|
|
112
|
+
this.$clusterTime = hello?.$clusterTime ?? null;
|
|
142
113
|
}
|
|
143
114
|
|
|
144
115
|
get hostAddress(): HostAddress {
|
|
145
|
-
|
|
146
|
-
else return new HostAddress(this.address);
|
|
116
|
+
return HostAddress.fromString(this.address);
|
|
147
117
|
}
|
|
148
118
|
|
|
149
119
|
get allHosts(): string[] {
|
|
@@ -179,15 +149,17 @@ export class ServerDescription {
|
|
|
179
149
|
* Determines if another `ServerDescription` is equal to this one per the rules defined
|
|
180
150
|
* in the {@link https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring.rst#serverdescription|SDAM spec}
|
|
181
151
|
*/
|
|
182
|
-
equals(other
|
|
152
|
+
equals(other?: ServerDescription | null): boolean {
|
|
153
|
+
// Despite using the comparator that would determine a nullish topologyVersion as greater than
|
|
154
|
+
// for equality we should only always perform direct equality comparison
|
|
183
155
|
const topologyVersionsEqual =
|
|
184
|
-
this.topologyVersion === other
|
|
185
|
-
compareTopologyVersion(this.topologyVersion, other
|
|
156
|
+
this.topologyVersion === other?.topologyVersion ||
|
|
157
|
+
compareTopologyVersion(this.topologyVersion, other?.topologyVersion) === 0;
|
|
186
158
|
|
|
187
|
-
const electionIdsEqual
|
|
188
|
-
this.electionId && other
|
|
189
|
-
?
|
|
190
|
-
: this.electionId === other
|
|
159
|
+
const electionIdsEqual =
|
|
160
|
+
this.electionId != null && other?.electionId != null
|
|
161
|
+
? compareObjectId(this.electionId, other.electionId) === 0
|
|
162
|
+
: this.electionId === other?.electionId;
|
|
191
163
|
|
|
192
164
|
return (
|
|
193
165
|
other != null &&
|
|
@@ -254,19 +226,37 @@ function tagsStrictEqual(tags: TagSet, tags2: TagSet): boolean {
|
|
|
254
226
|
/**
|
|
255
227
|
* Compares two topology versions.
|
|
256
228
|
*
|
|
257
|
-
*
|
|
229
|
+
* 1. If the response topologyVersion is unset or the ServerDescription's
|
|
230
|
+
* topologyVersion is null, the client MUST assume the response is more recent.
|
|
231
|
+
* 1. If the response's topologyVersion.processId is not equal to the
|
|
232
|
+
* ServerDescription's, the client MUST assume the response is more recent.
|
|
233
|
+
* 1. If the response's topologyVersion.processId is equal to the
|
|
234
|
+
* ServerDescription's, the client MUST use the counter field to determine
|
|
235
|
+
* which topologyVersion is more recent.
|
|
236
|
+
*
|
|
237
|
+
* ```ts
|
|
238
|
+
* currentTv < newTv === -1
|
|
239
|
+
* currentTv === newTv === 0
|
|
240
|
+
* currentTv > newTv === 1
|
|
241
|
+
* ```
|
|
258
242
|
*/
|
|
259
|
-
export function compareTopologyVersion(
|
|
260
|
-
|
|
243
|
+
export function compareTopologyVersion(
|
|
244
|
+
currentTv?: TopologyVersion | null,
|
|
245
|
+
newTv?: TopologyVersion | null
|
|
246
|
+
): 0 | -1 | 1 {
|
|
247
|
+
if (currentTv == null || newTv == null) {
|
|
261
248
|
return -1;
|
|
262
249
|
}
|
|
263
250
|
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
const lhsCounter = Long.isLong(lhs.counter) ? lhs.counter : Long.fromNumber(lhs.counter);
|
|
267
|
-
const rhsCounter = Long.isLong(rhs.counter) ? lhs.counter : Long.fromNumber(rhs.counter);
|
|
268
|
-
return lhsCounter.compare(rhsCounter);
|
|
251
|
+
if (!currentTv.processId.equals(newTv.processId)) {
|
|
252
|
+
return -1;
|
|
269
253
|
}
|
|
270
254
|
|
|
271
|
-
|
|
255
|
+
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
256
|
+
const currentCounter = Long.isLong(currentTv.counter)
|
|
257
|
+
? currentTv.counter
|
|
258
|
+
: Long.fromNumber(currentTv.counter);
|
|
259
|
+
const newCounter = Long.isLong(newTv.counter) ? newTv.counter : Long.fromNumber(newTv.counter);
|
|
260
|
+
|
|
261
|
+
return currentCounter.compare(newCounter);
|
|
272
262
|
}
|
package/src/sdam/srv_polling.ts
CHANGED