mongodb 4.3.1 → 4.5.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/README.md +7 -6
- package/lib/admin.js +5 -6
- package/lib/admin.js.map +1 -1
- package/lib/bulk/common.js +31 -7
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +29 -20
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +49 -7
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +12 -1
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongocr.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/plain.js.map +1 -1
- package/lib/cmap/auth/scram.js +1 -0
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/auth/x509.js.map +1 -1
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +0 -6
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +111 -86
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/errors.js.map +1 -1
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/stream_description.js +3 -0
- package/lib/cmap/stream_description.js.map +1 -1
- package/lib/collection.js +29 -28
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +53 -40
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +64 -42
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -2
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +4 -3
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +13 -13
- package/lib/db.js.map +1 -1
- package/lib/encrypter.js +17 -9
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +99 -48
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +2 -0
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +42 -51
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +9 -2
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +14 -27
- package/lib/mongo_client.js.map +1 -1
- package/lib/operations/add_user.js +8 -1
- package/lib/operations/add_user.js.map +1 -1
- package/lib/operations/aggregate.js +5 -0
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/collections.js.map +1 -1
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/common_functions.js +8 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/count.js.map +1 -1
- package/lib/operations/count_documents.js.map +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/delete.js +5 -3
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/drop.js.map +1 -1
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/eval.js.map +1 -1
- package/lib/operations/execute_operation.js +70 -79
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +3 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +5 -0
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/get_more.js +5 -0
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +8 -9
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +3 -1
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/is_capped.js.map +1 -1
- package/lib/operations/list_collections.js +10 -42
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +5 -0
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/map_reduce.js +1 -2
- package/lib/operations/map_reduce.js.map +1 -1
- package/lib/operations/operation.js +1 -3
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/options_operation.js.map +1 -1
- package/lib/operations/profiling_level.js.map +1 -1
- package/lib/operations/remove_user.js.map +1 -1
- package/lib/operations/rename.js +1 -1
- package/lib/operations/rename.js.map +1 -1
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/set_profiling_level.js.map +1 -1
- package/lib/operations/stats.js.map +1 -1
- package/lib/operations/update.js +5 -0
- package/lib/operations/update.js.map +1 -1
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/read_concern.js +1 -0
- package/lib/read_concern.js.map +1 -1
- package/lib/sdam/common.js +1 -7
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/events.js +1 -1
- package/lib/sdam/events.js.map +1 -1
- package/lib/sdam/monitor.js +1 -2
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +79 -57
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/topology.js +16 -33
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +1 -3
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +93 -68
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +21 -97
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +188 -29
- package/package.json +46 -46
- package/src/admin.ts +6 -10
- package/src/bulk/common.ts +42 -14
- package/src/bulk/unordered.ts +1 -1
- package/src/change_stream.ts +58 -42
- package/src/cmap/auth/gssapi.ts +58 -7
- package/src/cmap/auth/mongo_credentials.ts +17 -2
- package/src/cmap/auth/mongocr.ts +1 -1
- package/src/cmap/auth/mongodb_aws.ts +1 -1
- package/src/cmap/auth/plain.ts +1 -1
- package/src/cmap/auth/scram.ts +3 -2
- package/src/cmap/auth/x509.ts +6 -2
- package/src/cmap/commands.ts +3 -0
- package/src/cmap/connect.ts +2 -20
- package/src/cmap/connection.ts +162 -111
- package/src/cmap/errors.ts +2 -2
- package/src/cmap/message_stream.ts +2 -2
- package/src/cmap/stream_description.ts +4 -1
- package/src/collection.ts +37 -33
- package/src/connection_string.ts +77 -45
- package/src/cursor/abstract_cursor.ts +85 -56
- package/src/cursor/aggregation_cursor.ts +5 -5
- package/src/cursor/find_cursor.ts +19 -11
- package/src/db.ts +15 -19
- package/src/deps.ts +52 -0
- package/src/encrypter.ts +18 -10
- package/src/error.ts +145 -76
- package/src/gridfs/download.ts +3 -1
- package/src/gridfs/index.ts +51 -68
- package/src/gridfs/upload.ts +12 -12
- package/src/index.ts +10 -1
- package/src/mongo_client.ts +19 -41
- package/src/operations/add_user.ts +14 -3
- package/src/operations/aggregate.ts +15 -5
- package/src/operations/bulk_write.ts +6 -2
- package/src/operations/collections.ts +6 -2
- package/src/operations/command.ts +23 -8
- package/src/operations/common_functions.ts +8 -1
- package/src/operations/count.ts +6 -2
- package/src/operations/count_documents.ts +5 -1
- package/src/operations/create_collection.ts +6 -2
- package/src/operations/delete.ts +19 -13
- package/src/operations/distinct.ts +6 -2
- package/src/operations/drop.ts +12 -4
- package/src/operations/estimated_document_count.ts +11 -3
- package/src/operations/eval.ts +6 -2
- package/src/operations/execute_operation.ts +102 -101
- package/src/operations/find.ts +9 -5
- package/src/operations/find_and_modify.ts +21 -2
- package/src/operations/get_more.ts +20 -6
- package/src/operations/indexes.ts +54 -36
- package/src/operations/insert.ts +20 -6
- package/src/operations/is_capped.ts +6 -2
- package/src/operations/list_collections.ts +24 -59
- package/src/operations/list_databases.ts +13 -3
- package/src/operations/map_reduce.ts +7 -6
- package/src/operations/operation.ts +10 -9
- package/src/operations/options_operation.ts +6 -2
- package/src/operations/profiling_level.ts +6 -2
- package/src/operations/remove_user.ts +6 -2
- package/src/operations/rename.ts +7 -3
- package/src/operations/run_command.ts +6 -2
- package/src/operations/set_profiling_level.ts +6 -2
- package/src/operations/stats.ts +12 -4
- package/src/operations/update.ts +21 -9
- package/src/operations/validate_collection.ts +6 -2
- package/src/read_concern.ts +1 -0
- package/src/sdam/common.ts +0 -6
- package/src/sdam/events.ts +2 -2
- package/src/sdam/monitor.ts +4 -5
- package/src/sdam/server.ts +95 -90
- package/src/sdam/topology.ts +9 -53
- package/src/sdam/topology_description.ts +1 -3
- package/src/sessions.ts +108 -78
- package/src/utils.ts +38 -118
- package/tsconfig.json +40 -0
- package/mongodb.ts34.d.ts +0 -5649
package/src/sdam/topology.ts
CHANGED
|
@@ -50,7 +50,6 @@ import {
|
|
|
50
50
|
} from '../utils';
|
|
51
51
|
import {
|
|
52
52
|
_advanceClusterTime,
|
|
53
|
-
clearAndRemoveTimerFrom,
|
|
54
53
|
ClusterTime,
|
|
55
54
|
drainTimerQueue,
|
|
56
55
|
ServerType,
|
|
@@ -435,7 +434,12 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
435
434
|
|
|
436
435
|
// connect all known servers, then attempt server selection to connect
|
|
437
436
|
const serverDescriptions = Array.from(this.s.description.servers.values());
|
|
438
|
-
|
|
437
|
+
this.s.servers = new Map(
|
|
438
|
+
serverDescriptions.map(serverDescription => [
|
|
439
|
+
serverDescription.address,
|
|
440
|
+
createAndConnectServer(this, serverDescription)
|
|
441
|
+
])
|
|
442
|
+
);
|
|
439
443
|
|
|
440
444
|
// In load balancer mode we need to fake a server description getting
|
|
441
445
|
// emitted from the monitor, since the monitor doesn't exist.
|
|
@@ -459,7 +463,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
459
463
|
|
|
460
464
|
// TODO: NODE-2471
|
|
461
465
|
if (server && this.s.credentials) {
|
|
462
|
-
server.command(ns('admin.$cmd'), { ping: 1 }, err => {
|
|
466
|
+
server.command(ns('admin.$cmd'), { ping: 1 }, {}, err => {
|
|
463
467
|
if (err) {
|
|
464
468
|
typeof callback === 'function' ? callback(err) : this.emit(Topology.ERROR, err);
|
|
465
469
|
return;
|
|
@@ -549,27 +553,11 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
549
553
|
* @param callback - The callback used to indicate success or failure
|
|
550
554
|
* @returns An instance of a `Server` meeting the criteria of the predicate provided
|
|
551
555
|
*/
|
|
552
|
-
selectServer(options: SelectServerOptions, callback: Callback<Server>): void;
|
|
553
|
-
selectServer(
|
|
554
|
-
selector: string | ReadPreference | ServerSelector,
|
|
555
|
-
callback: Callback<Server>
|
|
556
|
-
): void;
|
|
557
556
|
selectServer(
|
|
558
557
|
selector: string | ReadPreference | ServerSelector,
|
|
559
558
|
options: SelectServerOptions,
|
|
560
559
|
callback: Callback<Server>
|
|
561
|
-
): void;
|
|
562
|
-
selectServer(
|
|
563
|
-
selector: string | ReadPreference | ServerSelector | SelectServerOptions,
|
|
564
|
-
_options?: SelectServerOptions | Callback<Server>,
|
|
565
|
-
_callback?: Callback<Server>
|
|
566
560
|
): void {
|
|
567
|
-
let options = _options as SelectServerOptions;
|
|
568
|
-
const callback = (_callback ?? _options) as Callback<Server>;
|
|
569
|
-
if (typeof options === 'function') {
|
|
570
|
-
options = {};
|
|
571
|
-
}
|
|
572
|
-
|
|
573
561
|
let serverSelector;
|
|
574
562
|
if (typeof selector !== 'function') {
|
|
575
563
|
if (typeof selector === 'string') {
|
|
@@ -667,6 +655,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
667
655
|
|
|
668
656
|
this.selectServer(
|
|
669
657
|
readPreferenceServerSelector(ReadPreference.primaryPreferred),
|
|
658
|
+
{},
|
|
670
659
|
(err, server) => {
|
|
671
660
|
if (err || !server) {
|
|
672
661
|
if (typeof callback === 'function') callback(err);
|
|
@@ -875,13 +864,8 @@ function randomSelection(array: ServerDescription[]): ServerDescription {
|
|
|
875
864
|
*
|
|
876
865
|
* @param topology - The topology that this server belongs to
|
|
877
866
|
* @param serverDescription - The description for the server to initialize and connect to
|
|
878
|
-
* @param connectDelay - Time to wait before attempting initial connection
|
|
879
867
|
*/
|
|
880
|
-
function createAndConnectServer(
|
|
881
|
-
topology: Topology,
|
|
882
|
-
serverDescription: ServerDescription,
|
|
883
|
-
connectDelay?: number
|
|
884
|
-
) {
|
|
868
|
+
function createAndConnectServer(topology: Topology, serverDescription: ServerDescription) {
|
|
885
869
|
topology.emit(
|
|
886
870
|
Topology.SERVER_OPENING,
|
|
887
871
|
new ServerOpeningEvent(topology.s.id, serverDescription.address)
|
|
@@ -894,38 +878,10 @@ function createAndConnectServer(
|
|
|
894
878
|
|
|
895
879
|
server.on(Server.DESCRIPTION_RECEIVED, description => topology.serverUpdateHandler(description));
|
|
896
880
|
|
|
897
|
-
if (connectDelay) {
|
|
898
|
-
const connectTimer = setTimeout(() => {
|
|
899
|
-
clearAndRemoveTimerFrom(connectTimer, topology.s.connectionTimers);
|
|
900
|
-
server.connect();
|
|
901
|
-
}, connectDelay);
|
|
902
|
-
|
|
903
|
-
topology.s.connectionTimers.add(connectTimer);
|
|
904
|
-
return server;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
881
|
server.connect();
|
|
908
882
|
return server;
|
|
909
883
|
}
|
|
910
884
|
|
|
911
|
-
/**
|
|
912
|
-
* Create `Server` instances for all initially known servers, connect them, and assign
|
|
913
|
-
* them to the passed in `Topology`.
|
|
914
|
-
*
|
|
915
|
-
* @param topology - The topology responsible for the servers
|
|
916
|
-
* @param serverDescriptions - A list of server descriptions to connect
|
|
917
|
-
*/
|
|
918
|
-
function connectServers(topology: Topology, serverDescriptions: ServerDescription[]) {
|
|
919
|
-
topology.s.servers = serverDescriptions.reduce(
|
|
920
|
-
(servers: Map<string, Server>, serverDescription: ServerDescription) => {
|
|
921
|
-
const server = createAndConnectServer(topology, serverDescription);
|
|
922
|
-
servers.set(serverDescription.address, server);
|
|
923
|
-
return servers;
|
|
924
|
-
},
|
|
925
|
-
new Map<string, Server>()
|
|
926
|
-
);
|
|
927
|
-
}
|
|
928
|
-
|
|
929
885
|
/**
|
|
930
886
|
* @param topology - Topology to update.
|
|
931
887
|
* @param incomingServerDescription - New server description.
|
|
@@ -58,9 +58,6 @@ export class TopologyDescription {
|
|
|
58
58
|
) {
|
|
59
59
|
options = options ?? {};
|
|
60
60
|
|
|
61
|
-
// TODO: consider assigning all these values to a temporary value `s` which
|
|
62
|
-
// we use `Object.freeze` on, ensuring the internal state of this type
|
|
63
|
-
// is immutable.
|
|
64
61
|
this.type = topologyType ?? TopologyType.Unknown;
|
|
65
62
|
this.servers = serverDescriptions ?? new Map();
|
|
66
63
|
this.stale = false;
|
|
@@ -321,6 +318,7 @@ export class TopologyDescription {
|
|
|
321
318
|
if (descriptionsWithError.length > 0) {
|
|
322
319
|
return descriptionsWithError[0].error;
|
|
323
320
|
}
|
|
321
|
+
return;
|
|
324
322
|
}
|
|
325
323
|
|
|
326
324
|
/**
|
package/src/sessions.ts
CHANGED
|
@@ -6,16 +6,14 @@ import { PINNED, UNPINNED } from './constants';
|
|
|
6
6
|
import type { AbstractCursor } from './cursor/abstract_cursor';
|
|
7
7
|
import {
|
|
8
8
|
AnyError,
|
|
9
|
-
isRetryableEndTransactionError,
|
|
10
|
-
isRetryableError,
|
|
11
9
|
MongoAPIError,
|
|
12
10
|
MongoCompatibilityError,
|
|
13
11
|
MONGODB_ERROR_CODES,
|
|
14
12
|
MongoDriverError,
|
|
15
13
|
MongoError,
|
|
14
|
+
MongoErrorLabel,
|
|
16
15
|
MongoExpiredSessionError,
|
|
17
16
|
MongoInvalidArgumentError,
|
|
18
|
-
MongoNetworkError,
|
|
19
17
|
MongoRuntimeError,
|
|
20
18
|
MongoServerError,
|
|
21
19
|
MongoTransactionError,
|
|
@@ -41,24 +39,9 @@ import {
|
|
|
41
39
|
now,
|
|
42
40
|
uuidV4
|
|
43
41
|
} from './utils';
|
|
44
|
-
import type { WriteConcern } from './write_concern';
|
|
45
42
|
|
|
46
43
|
const minWireVersionForShardedTransactions = 8;
|
|
47
44
|
|
|
48
|
-
function assertAlive(session: ClientSession, callback?: Callback): boolean {
|
|
49
|
-
if (session.serverSession == null) {
|
|
50
|
-
const error = new MongoExpiredSessionError();
|
|
51
|
-
if (typeof callback === 'function') {
|
|
52
|
-
callback(error);
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
45
|
/** @public */
|
|
63
46
|
export interface ClientSessionOptions {
|
|
64
47
|
/** Whether causal consistency should be enabled on this session */
|
|
@@ -92,6 +75,8 @@ const kSnapshotTime = Symbol('snapshotTime');
|
|
|
92
75
|
const kSnapshotEnabled = Symbol('snapshotEnabled');
|
|
93
76
|
/** @internal */
|
|
94
77
|
const kPinnedConnection = Symbol('pinnedConnection');
|
|
78
|
+
/** @internal Accumulates total number of increments to add to txnNumber when applying session to command */
|
|
79
|
+
const kTxnNumberIncrement = Symbol('txnNumberIncrement');
|
|
95
80
|
|
|
96
81
|
/** @public */
|
|
97
82
|
export interface EndSessionOptions {
|
|
@@ -126,13 +111,15 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
126
111
|
defaultTransactionOptions: TransactionOptions;
|
|
127
112
|
transaction: Transaction;
|
|
128
113
|
/** @internal */
|
|
129
|
-
[kServerSession]
|
|
114
|
+
[kServerSession]: ServerSession | null;
|
|
130
115
|
/** @internal */
|
|
131
116
|
[kSnapshotTime]?: Timestamp;
|
|
132
117
|
/** @internal */
|
|
133
118
|
[kSnapshotEnabled] = false;
|
|
134
119
|
/** @internal */
|
|
135
120
|
[kPinnedConnection]?: Connection;
|
|
121
|
+
/** @internal */
|
|
122
|
+
[kTxnNumberIncrement]: number;
|
|
136
123
|
|
|
137
124
|
/**
|
|
138
125
|
* Create a client session.
|
|
@@ -175,7 +162,10 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
175
162
|
this.sessionPool = sessionPool;
|
|
176
163
|
this.hasEnded = false;
|
|
177
164
|
this.clientOptions = clientOptions;
|
|
178
|
-
|
|
165
|
+
|
|
166
|
+
this.explicit = !!options.explicit;
|
|
167
|
+
this[kServerSession] = this.explicit ? this.sessionPool.acquire() : null;
|
|
168
|
+
this[kTxnNumberIncrement] = 0;
|
|
179
169
|
|
|
180
170
|
this.supports = {
|
|
181
171
|
causalConsistency: options.snapshot !== true && options.causalConsistency !== false
|
|
@@ -184,7 +174,6 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
184
174
|
this.clusterTime = options.initialClusterTime;
|
|
185
175
|
|
|
186
176
|
this.operationTime = undefined;
|
|
187
|
-
this.explicit = !!options.explicit;
|
|
188
177
|
this.owner = options.owner;
|
|
189
178
|
this.defaultTransactionOptions = Object.assign({}, options.defaultTransactionOptions);
|
|
190
179
|
this.transaction = new Transaction();
|
|
@@ -192,16 +181,22 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
192
181
|
|
|
193
182
|
/** The server id associated with this session */
|
|
194
183
|
get id(): ServerSessionId | undefined {
|
|
195
|
-
return this
|
|
184
|
+
return this[kServerSession]?.id;
|
|
196
185
|
}
|
|
197
186
|
|
|
198
187
|
get serverSession(): ServerSession {
|
|
199
|
-
|
|
200
|
-
|
|
188
|
+
let serverSession = this[kServerSession];
|
|
189
|
+
if (serverSession == null) {
|
|
190
|
+
if (this.explicit) {
|
|
191
|
+
throw new MongoRuntimeError('Unexpected null serverSession for an explicit session');
|
|
192
|
+
}
|
|
193
|
+
if (this.hasEnded) {
|
|
194
|
+
throw new MongoRuntimeError('Unexpected null serverSession for an ended implicit session');
|
|
195
|
+
}
|
|
196
|
+
serverSession = this.sessionPool.acquire();
|
|
197
|
+
this[kServerSession] = serverSession;
|
|
201
198
|
}
|
|
202
|
-
|
|
203
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
204
|
-
return this[kServerSession]!;
|
|
199
|
+
return serverSession;
|
|
205
200
|
}
|
|
206
201
|
|
|
207
202
|
/** Whether or not this session is configured for snapshot reads */
|
|
@@ -270,9 +265,15 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
270
265
|
const completeEndSession = () => {
|
|
271
266
|
maybeClearPinnedConnection(this, finalOptions);
|
|
272
267
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
268
|
+
const serverSession = this[kServerSession];
|
|
269
|
+
if (serverSession != null) {
|
|
270
|
+
// release the server session back to the pool
|
|
271
|
+
this.sessionPool.release(serverSession);
|
|
272
|
+
// Make sure a new serverSession never makes it on to the ClientSession
|
|
273
|
+
Object.defineProperty(this, kServerSession, {
|
|
274
|
+
value: ServerSession.clone(serverSession)
|
|
275
|
+
});
|
|
276
|
+
}
|
|
276
277
|
|
|
277
278
|
// mark the session as ended, and emit a signal
|
|
278
279
|
this.hasEnded = true;
|
|
@@ -282,7 +283,9 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
282
283
|
done();
|
|
283
284
|
};
|
|
284
285
|
|
|
285
|
-
if (this.
|
|
286
|
+
if (this.inTransaction()) {
|
|
287
|
+
// If we've reached endSession and the transaction is still active
|
|
288
|
+
// by default we abort it
|
|
286
289
|
this.abortTransaction(err => {
|
|
287
290
|
if (err) return done(err);
|
|
288
291
|
completeEndSession();
|
|
@@ -356,12 +359,16 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
356
359
|
return this.id.id.buffer.equals(session.id.id.buffer);
|
|
357
360
|
}
|
|
358
361
|
|
|
359
|
-
/**
|
|
362
|
+
/**
|
|
363
|
+
* Increment the transaction number on the internal ServerSession
|
|
364
|
+
*
|
|
365
|
+
* @privateRemarks
|
|
366
|
+
* This helper increments a value stored on the client session that will be
|
|
367
|
+
* added to the serverSession's txnNumber upon applying it to a command.
|
|
368
|
+
* This is because the serverSession is lazily acquired after a connection is obtained
|
|
369
|
+
*/
|
|
360
370
|
incrementTransactionNumber(): void {
|
|
361
|
-
|
|
362
|
-
this.serverSession.txnNumber =
|
|
363
|
-
typeof this.serverSession.txnNumber === 'number' ? this.serverSession.txnNumber + 1 : 0;
|
|
364
|
-
}
|
|
371
|
+
this[kTxnNumberIncrement] += 1;
|
|
365
372
|
}
|
|
366
373
|
|
|
367
374
|
/** @returns whether this session is currently in a transaction or not */
|
|
@@ -379,7 +386,6 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
379
386
|
throw new MongoCompatibilityError('Transactions are not allowed with snapshot sessions');
|
|
380
387
|
}
|
|
381
388
|
|
|
382
|
-
assertAlive(this);
|
|
383
389
|
if (this.inTransaction()) {
|
|
384
390
|
throw new MongoTransactionError('Transaction already in progress');
|
|
385
391
|
}
|
|
@@ -507,7 +513,7 @@ export function maybeClearPinnedConnection(
|
|
|
507
513
|
session.inTransaction() &&
|
|
508
514
|
error &&
|
|
509
515
|
error instanceof MongoError &&
|
|
510
|
-
error.hasErrorLabel(
|
|
516
|
+
error.hasErrorLabel(MongoErrorLabel.TransientTransactionError)
|
|
511
517
|
) {
|
|
512
518
|
return;
|
|
513
519
|
}
|
|
@@ -559,11 +565,11 @@ function attemptTransactionCommit<T>(
|
|
|
559
565
|
hasNotTimedOut(startTime, MAX_WITH_TRANSACTION_TIMEOUT) &&
|
|
560
566
|
!isMaxTimeMSExpiredError(err)
|
|
561
567
|
) {
|
|
562
|
-
if (err.hasErrorLabel(
|
|
568
|
+
if (err.hasErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult)) {
|
|
563
569
|
return attemptTransactionCommit(session, startTime, fn, options);
|
|
564
570
|
}
|
|
565
571
|
|
|
566
|
-
if (err.hasErrorLabel(
|
|
572
|
+
if (err.hasErrorLabel(MongoErrorLabel.TransientTransactionError)) {
|
|
567
573
|
return attemptTransaction(session, startTime, fn, options);
|
|
568
574
|
}
|
|
569
575
|
}
|
|
@@ -617,20 +623,20 @@ function attemptTransaction<TSchema>(
|
|
|
617
623
|
function maybeRetryOrThrow(err: MongoError): Promise<any> {
|
|
618
624
|
if (
|
|
619
625
|
err instanceof MongoError &&
|
|
620
|
-
err.hasErrorLabel(
|
|
626
|
+
err.hasErrorLabel(MongoErrorLabel.TransientTransactionError) &&
|
|
621
627
|
hasNotTimedOut(startTime, MAX_WITH_TRANSACTION_TIMEOUT)
|
|
622
628
|
) {
|
|
623
629
|
return attemptTransaction(session, startTime, fn, options);
|
|
624
630
|
}
|
|
625
631
|
|
|
626
632
|
if (isMaxTimeMSExpiredError(err)) {
|
|
627
|
-
err.addErrorLabel(
|
|
633
|
+
err.addErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult);
|
|
628
634
|
}
|
|
629
635
|
|
|
630
636
|
throw err;
|
|
631
637
|
}
|
|
632
638
|
|
|
633
|
-
if (session.
|
|
639
|
+
if (session.inTransaction()) {
|
|
634
640
|
return session.abortTransaction().then(() => maybeRetryOrThrow(err));
|
|
635
641
|
}
|
|
636
642
|
|
|
@@ -639,12 +645,11 @@ function attemptTransaction<TSchema>(
|
|
|
639
645
|
);
|
|
640
646
|
}
|
|
641
647
|
|
|
642
|
-
function endTransaction(
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
+
function endTransaction(
|
|
649
|
+
session: ClientSession,
|
|
650
|
+
commandName: 'abortTransaction' | 'commitTransaction',
|
|
651
|
+
callback: Callback<Document>
|
|
652
|
+
) {
|
|
648
653
|
// handle any initial problematic cases
|
|
649
654
|
const txnState = session.transaction.state;
|
|
650
655
|
|
|
@@ -717,7 +722,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C
|
|
|
717
722
|
Object.assign(command, { maxTimeMS: session.transaction.options.maxTimeMS });
|
|
718
723
|
}
|
|
719
724
|
|
|
720
|
-
function commandHandler(
|
|
725
|
+
function commandHandler(error?: Error, result?: Document) {
|
|
721
726
|
if (commandName !== 'commitTransaction') {
|
|
722
727
|
session.transaction.transition(TxnState.TRANSACTION_ABORTED);
|
|
723
728
|
if (session.loadBalanced) {
|
|
@@ -729,47 +734,45 @@ function endTransaction(session: ClientSession, commandName: string, callback: C
|
|
|
729
734
|
}
|
|
730
735
|
|
|
731
736
|
session.transaction.transition(TxnState.TRANSACTION_COMMITTED);
|
|
732
|
-
if (
|
|
737
|
+
if (error instanceof MongoError) {
|
|
733
738
|
if (
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
isMaxTimeMSExpiredError(e)
|
|
739
|
+
error.hasErrorLabel(MongoErrorLabel.RetryableWriteError) ||
|
|
740
|
+
error instanceof MongoWriteConcernError ||
|
|
741
|
+
isMaxTimeMSExpiredError(error)
|
|
738
742
|
) {
|
|
739
|
-
if (isUnknownTransactionCommitResult(
|
|
740
|
-
|
|
743
|
+
if (isUnknownTransactionCommitResult(error)) {
|
|
744
|
+
error.addErrorLabel(MongoErrorLabel.UnknownTransactionCommitResult);
|
|
741
745
|
|
|
742
746
|
// per txns spec, must unpin session in this case
|
|
743
|
-
session.unpin({ error
|
|
747
|
+
session.unpin({ error });
|
|
744
748
|
}
|
|
745
|
-
} else if (
|
|
746
|
-
session.unpin({ error
|
|
749
|
+
} else if (error.hasErrorLabel(MongoErrorLabel.TransientTransactionError)) {
|
|
750
|
+
session.unpin({ error });
|
|
747
751
|
}
|
|
748
752
|
}
|
|
749
753
|
|
|
750
|
-
callback(
|
|
754
|
+
callback(error, result);
|
|
751
755
|
}
|
|
752
756
|
|
|
753
|
-
// Assumption here that commandName is "commitTransaction" or "abortTransaction"
|
|
754
757
|
if (session.transaction.recoveryToken) {
|
|
755
758
|
command.recoveryToken = session.transaction.recoveryToken;
|
|
756
759
|
}
|
|
757
760
|
|
|
758
761
|
// send the command
|
|
759
762
|
executeOperation(
|
|
760
|
-
session
|
|
763
|
+
session,
|
|
761
764
|
new RunAdminCommandOperation(undefined, command, {
|
|
762
765
|
session,
|
|
763
766
|
readPreference: ReadPreference.primary,
|
|
764
767
|
bypassPinningCheck: true
|
|
765
768
|
}),
|
|
766
|
-
(
|
|
769
|
+
(error, result) => {
|
|
767
770
|
if (command.abortTransaction) {
|
|
768
771
|
// always unpin on abort regardless of command outcome
|
|
769
772
|
session.unpin();
|
|
770
773
|
}
|
|
771
774
|
|
|
772
|
-
if (
|
|
775
|
+
if (error instanceof MongoError && error.hasErrorLabel(MongoErrorLabel.RetryableWriteError)) {
|
|
773
776
|
// SPEC-1185: apply majority write concern when retrying commitTransaction
|
|
774
777
|
if (command.commitTransaction) {
|
|
775
778
|
// per txns spec, must unpin session in this case
|
|
@@ -781,17 +784,17 @@ function endTransaction(session: ClientSession, commandName: string, callback: C
|
|
|
781
784
|
}
|
|
782
785
|
|
|
783
786
|
return executeOperation(
|
|
784
|
-
session
|
|
787
|
+
session,
|
|
785
788
|
new RunAdminCommandOperation(undefined, command, {
|
|
786
789
|
session,
|
|
787
790
|
readPreference: ReadPreference.primary,
|
|
788
791
|
bypassPinningCheck: true
|
|
789
792
|
}),
|
|
790
|
-
|
|
793
|
+
commandHandler
|
|
791
794
|
);
|
|
792
795
|
}
|
|
793
796
|
|
|
794
|
-
commandHandler(
|
|
797
|
+
commandHandler(error, result);
|
|
795
798
|
}
|
|
796
799
|
);
|
|
797
800
|
}
|
|
@@ -832,6 +835,30 @@ export class ServerSession {
|
|
|
832
835
|
|
|
833
836
|
return idleTimeMinutes > sessionTimeoutMinutes - 1;
|
|
834
837
|
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* @internal
|
|
841
|
+
* Cloning meant to keep a readable reference to the server session data
|
|
842
|
+
* after ClientSession has ended
|
|
843
|
+
*/
|
|
844
|
+
static clone(serverSession: ServerSession): Readonly<ServerSession> {
|
|
845
|
+
const arrayBuffer = new ArrayBuffer(16);
|
|
846
|
+
const idBytes = Buffer.from(arrayBuffer);
|
|
847
|
+
idBytes.set(serverSession.id.id.buffer);
|
|
848
|
+
|
|
849
|
+
const id = new Binary(idBytes, serverSession.id.id.sub_type);
|
|
850
|
+
|
|
851
|
+
// Manual prototype construction to avoid modifying the constructor of this class
|
|
852
|
+
return Object.setPrototypeOf(
|
|
853
|
+
{
|
|
854
|
+
id: { id },
|
|
855
|
+
lastUse: serverSession.lastUse,
|
|
856
|
+
txnNumber: serverSession.txnNumber,
|
|
857
|
+
isDirty: serverSession.isDirty
|
|
858
|
+
},
|
|
859
|
+
ServerSession.prototype
|
|
860
|
+
);
|
|
861
|
+
}
|
|
835
862
|
}
|
|
836
863
|
|
|
837
864
|
/**
|
|
@@ -936,26 +963,27 @@ export class ServerSessionPool {
|
|
|
936
963
|
* @param session - the session tracking transaction state
|
|
937
964
|
* @param command - the command to decorate
|
|
938
965
|
* @param options - Optional settings passed to calling operation
|
|
966
|
+
*
|
|
967
|
+
* @internal
|
|
939
968
|
*/
|
|
940
969
|
export function applySession(
|
|
941
970
|
session: ClientSession,
|
|
942
971
|
command: Document,
|
|
943
|
-
options
|
|
972
|
+
options: CommandOptions
|
|
944
973
|
): MongoDriverError | undefined {
|
|
945
|
-
// TODO: merge this with `assertAlive`, did not want to throw a try/catch here
|
|
946
974
|
if (session.hasEnded) {
|
|
947
975
|
return new MongoExpiredSessionError();
|
|
948
976
|
}
|
|
949
977
|
|
|
978
|
+
// May acquire serverSession here
|
|
950
979
|
const serverSession = session.serverSession;
|
|
951
980
|
if (serverSession == null) {
|
|
952
981
|
return new MongoRuntimeError('Unable to acquire server session');
|
|
953
982
|
}
|
|
954
983
|
|
|
955
|
-
|
|
956
|
-
// FIXME: NODE-2781, this check for write concern shouldn't be happening here, but instead during command construction
|
|
957
|
-
if (options && options.writeConcern && (options.writeConcern as WriteConcern).w === 0) {
|
|
984
|
+
if (options.writeConcern?.w === 0) {
|
|
958
985
|
if (session && session.explicit) {
|
|
986
|
+
// Error if user provided an explicit session to an unacknowledged write (SPEC-1019)
|
|
959
987
|
return new MongoAPIError('Cannot have explicit session with unacknowledged writes');
|
|
960
988
|
}
|
|
961
989
|
return;
|
|
@@ -965,15 +993,16 @@ export function applySession(
|
|
|
965
993
|
serverSession.lastUse = now();
|
|
966
994
|
command.lsid = serverSession.id;
|
|
967
995
|
|
|
968
|
-
|
|
969
|
-
const
|
|
970
|
-
const isRetryableWrite = options?.willRetryWrite || false;
|
|
996
|
+
const inTxnOrTxnCommand = session.inTransaction() || isTransactionCommand(command);
|
|
997
|
+
const isRetryableWrite = !!options.willRetryWrite;
|
|
971
998
|
|
|
972
|
-
if (
|
|
999
|
+
if (isRetryableWrite || inTxnOrTxnCommand) {
|
|
1000
|
+
serverSession.txnNumber += session[kTxnNumberIncrement];
|
|
1001
|
+
session[kTxnNumberIncrement] = 0;
|
|
973
1002
|
command.txnNumber = Long.fromNumber(serverSession.txnNumber);
|
|
974
1003
|
}
|
|
975
1004
|
|
|
976
|
-
if (!
|
|
1005
|
+
if (!inTxnOrTxnCommand) {
|
|
977
1006
|
if (session.transaction.state !== TxnState.NO_TRANSACTION) {
|
|
978
1007
|
session.transaction.transition(TxnState.NO_TRANSACTION);
|
|
979
1008
|
}
|
|
@@ -1015,6 +1044,7 @@ export function applySession(
|
|
|
1015
1044
|
Object.assign(command.readConcern, { afterClusterTime: session.operationTime });
|
|
1016
1045
|
}
|
|
1017
1046
|
}
|
|
1047
|
+
return;
|
|
1018
1048
|
}
|
|
1019
1049
|
|
|
1020
1050
|
export function updateSessionFromResponse(session: ClientSession, document: Document): void {
|