mongodb 6.8.2 → 6.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/README.md +14 -1
- package/lib/beta.d.ts +7905 -0
- package/lib/beta.js +21 -0
- package/lib/beta.js.map +1 -0
- package/lib/bson.js +5 -5
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +16 -21
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/ordered.js.map +1 -1
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +10 -8
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +14 -3
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +25 -7
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/crypto_callbacks.js +6 -6
- package/lib/client-side-encryption/crypto_callbacks.js.map +1 -1
- package/lib/client-side-encryption/mongocryptd_manager.js +9 -5
- package/lib/client-side-encryption/mongocryptd_manager.js.map +1 -1
- package/lib/client-side-encryption/providers/aws.js +1 -2
- package/lib/client-side-encryption/providers/aws.js.map +1 -1
- package/lib/client-side-encryption/providers/azure.js +5 -5
- package/lib/client-side-encryption/providers/azure.js.map +1 -1
- package/lib/client-side-encryption/providers/gcp.js +1 -2
- package/lib/client-side-encryption/providers/gcp.js.map +1 -1
- package/lib/client-side-encryption/providers/index.js +2 -3
- package/lib/client-side-encryption/providers/index.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +9 -4
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/auth_provider.js.map +1 -1
- package/lib/cmap/auth/aws_temporary_credentials.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +4 -4
- package/lib/cmap/auth/gssapi.js.map +1 -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/mongodb_oidc/automated_callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/azure_machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +0 -2
- package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/command_builders.js +2 -3
- package/lib/cmap/auth/mongodb_oidc/command_builders.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/gcp_machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/human_callback_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js +0 -2
- package/lib/cmap/auth/mongodb_oidc/machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/token_cache.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/auth/plain.js.map +1 -1
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/auth/x509.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +62 -5
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +10 -7
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +3 -5
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +11 -9
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/connection_pool_events.js +7 -3
- package/lib/cmap/connection_pool_events.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +5 -5
- package/lib/cmap/handshake/client_metadata.js.map +1 -1
- package/lib/cmap/metrics.js +1 -1
- package/lib/cmap/metrics.js.map +1 -1
- package/lib/cmap/stream_description.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +5 -5
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/cmap/wire_protocol/constants.js +2 -2
- package/lib/cmap/wire_protocol/on_data.js +1 -2
- package/lib/cmap/wire_protocol/on_data.js.map +1 -1
- package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +4 -4
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/cmap/wire_protocol/shared.js +2 -3
- package/lib/cmap/wire_protocol/shared.js.map +1 -1
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +12 -6
- package/lib/connection_string.js.map +1 -1
- package/lib/constants.js +1 -0
- package/lib/constants.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +21 -6
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +1 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +3 -3
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +1 -1
- package/lib/db.js.map +1 -1
- package/lib/deps.js +16 -8
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +19 -14
- package/lib/error.js.map +1 -1
- package/lib/explain.js.map +1 -1
- package/lib/gridfs/download.js +1 -4
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +1 -1
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +0 -4
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +4 -2
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +15 -1
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_client_auth_providers.js.map +1 -1
- package/lib/mongo_logger.js +8 -8
- package/lib/mongo_logger.js.map +1 -1
- package/lib/mongo_types.js +1 -0
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/aggregate.js +1 -0
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/client_bulk_write/command_builder.js +198 -0
- package/lib/operations/client_bulk_write/command_builder.js.map +1 -0
- package/lib/operations/client_bulk_write/common.js +3 -0
- package/lib/operations/client_bulk_write/common.js.map +1 -0
- package/lib/operations/collections.js.map +1 -1
- package/lib/operations/command.js +1 -1
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/count.js.map +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/delete.js +2 -2
- 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/execute_operation.js +111 -109
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +2 -8
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/is_capped.js.map +1 -1
- package/lib/operations/kill_cursors.js.map +1 -1
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/operation.js +5 -5
- 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/search_indexes/drop.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 +2 -2
- package/lib/operations/update.js.map +1 -1
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/read_concern.js.map +1 -1
- package/lib/read_preference.js +1 -1
- package/lib/read_preference.js.map +1 -1
- package/lib/resource_management.js +58 -0
- package/lib/resource_management.js.map +1 -0
- package/lib/sdam/common.js +3 -3
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/monitor.js +1 -5
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +2 -2
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +3 -3
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/server_selection.js +5 -5
- package/lib/sdam/server_selection.js.map +1 -1
- package/lib/sdam/srv_polling.js +2 -3
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +1 -1
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +221 -218
- package/lib/sessions.js.map +1 -1
- package/lib/sort.js +2 -3
- package/lib/sort.js.map +1 -1
- package/lib/timeout.js +0 -1
- package/lib/timeout.js.map +1 -1
- package/lib/transactions.js +2 -2
- package/lib/transactions.js.map +1 -1
- package/lib/utils.js +49 -51
- package/lib/utils.js.map +1 -1
- package/lib/write_concern.js +2 -2
- package/lib/write_concern.js.map +1 -1
- package/mongodb.d.ts +150 -142
- package/package.json +26 -27
- package/src/beta.ts +22 -0
- package/src/bson.ts +1 -2
- package/src/bulk/common.ts +18 -18
- package/src/change_stream.ts +33 -15
- package/src/client-side-encryption/auto_encrypter.ts +18 -82
- package/src/client-side-encryption/client_encryption.ts +51 -54
- package/src/client-side-encryption/mongocryptd_manager.ts +10 -6
- package/src/client-side-encryption/state_machine.ts +28 -6
- package/src/cmap/auth/gssapi.ts +1 -1
- package/src/cmap/auth/mongodb_aws.ts +2 -2
- package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +2 -2
- package/src/cmap/auth/mongodb_oidc/machine_workflow.ts +2 -2
- package/src/cmap/commands.ts +70 -5
- package/src/cmap/connect.ts +4 -1
- package/src/cmap/connection.ts +2 -2
- package/src/cmap/connection_pool.ts +17 -9
- package/src/cmap/connection_pool_events.ts +34 -2
- package/src/cmap/handshake/client_metadata.ts +1 -1
- package/src/cmap/wire_protocol/constants.ts +2 -2
- package/src/cmap/wire_protocol/shared.ts +1 -2
- package/src/collection.ts +16 -15
- package/src/connection_string.ts +10 -3
- package/src/constants.ts +1 -0
- package/src/cursor/abstract_cursor.ts +38 -13
- package/src/cursor/aggregation_cursor.ts +6 -4
- package/src/deps.ts +8 -1
- package/src/error.ts +33 -14
- package/src/gridfs/download.ts +28 -4
- package/src/gridfs/upload.ts +1 -6
- package/src/index.ts +5 -1
- package/src/mongo_client.ts +29 -5
- package/src/mongo_logger.ts +5 -3
- package/src/mongo_types.ts +69 -68
- package/src/operations/aggregate.ts +2 -1
- package/src/operations/bulk_write.ts +2 -2
- package/src/operations/client_bulk_write/command_builder.ts +283 -0
- package/src/operations/client_bulk_write/common.ts +146 -0
- package/src/operations/command.ts +1 -1
- package/src/operations/execute_operation.ts +137 -131
- package/src/operations/find_and_modify.ts +2 -7
- package/src/operations/insert.ts +3 -4
- package/src/operations/operation.ts +7 -10
- package/src/operations/search_indexes/drop.ts +4 -1
- package/src/resource_management.ts +74 -0
- package/src/sdam/monitor.ts +3 -5
- package/src/sdam/server.ts +1 -1
- package/src/sdam/server_description.ts +5 -6
- package/src/sdam/srv_polling.ts +1 -2
- package/src/sessions.ts +291 -277
- package/src/sort.ts +1 -1
- package/src/timeout.ts +0 -1
- package/src/transactions.ts +1 -2
- package/src/utils.ts +9 -4
- package/src/write_concern.ts +2 -2
- package/tsconfig.json +2 -1
|
@@ -24,16 +24,15 @@ import {
|
|
|
24
24
|
} from '../sdam/server_selection';
|
|
25
25
|
import type { Topology } from '../sdam/topology';
|
|
26
26
|
import type { ClientSession } from '../sessions';
|
|
27
|
-
import {
|
|
27
|
+
import { supportsRetryableWrites } from '../utils';
|
|
28
28
|
import { AbstractOperation, Aspect } from './operation';
|
|
29
29
|
|
|
30
30
|
const MMAPv1_RETRY_WRITES_ERROR_CODE = MONGODB_ERROR_CODES.IllegalOperation;
|
|
31
31
|
const MMAPv1_RETRY_WRITES_ERROR_MESSAGE =
|
|
32
32
|
'This MongoDB deployment does not support retryable writes. Please add retryWrites=false to your connection string.';
|
|
33
33
|
|
|
34
|
-
type ResultTypeFromOperation<TOperation> =
|
|
35
|
-
? K
|
|
36
|
-
: never;
|
|
34
|
+
type ResultTypeFromOperation<TOperation> =
|
|
35
|
+
TOperation extends AbstractOperation<infer K> ? K : never;
|
|
37
36
|
|
|
38
37
|
/**
|
|
39
38
|
* Executes the given operation with provided arguments.
|
|
@@ -45,10 +44,9 @@ type ResultTypeFromOperation<TOperation> = TOperation extends AbstractOperation<
|
|
|
45
44
|
* not provided.
|
|
46
45
|
*
|
|
47
46
|
* The expectation is that this function:
|
|
48
|
-
* - Connects the MongoClient if it has not already been connected
|
|
47
|
+
* - Connects the MongoClient if it has not already been connected, see {@link autoConnect}
|
|
49
48
|
* - Creates a session if none is provided and cleans up the session it creates
|
|
50
|
-
* -
|
|
51
|
-
* - Retries an operation if it fails for certain errors, see {@link retryOperation}
|
|
49
|
+
* - Tries an operation and retries under certain conditions, see {@link tryOperation}
|
|
52
50
|
*
|
|
53
51
|
* @typeParam T - The operation's type
|
|
54
52
|
* @typeParam TResult - The type of the operation's result, calculated from T
|
|
@@ -65,23 +63,7 @@ export async function executeOperation<
|
|
|
65
63
|
throw new MongoRuntimeError('This method requires a valid operation instance');
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
|
|
69
|
-
// Auto connect on operation
|
|
70
|
-
if (client.s.hasBeenClosed) {
|
|
71
|
-
throw new MongoNotConnectedError('Client must be connected before running operations');
|
|
72
|
-
}
|
|
73
|
-
client.s.options[Symbol.for('@@mdb.skipPingOnConnect')] = true;
|
|
74
|
-
try {
|
|
75
|
-
await client.connect();
|
|
76
|
-
} finally {
|
|
77
|
-
delete client.s.options[Symbol.for('@@mdb.skipPingOnConnect')];
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const { topology } = client;
|
|
82
|
-
if (topology == null) {
|
|
83
|
-
throw new MongoRuntimeError('client.connect did not create a topology but also did not throw');
|
|
84
|
-
}
|
|
66
|
+
const topology = await autoConnect(client);
|
|
85
67
|
|
|
86
68
|
// The driver sessions spec mandates that we implicitly create sessions for operations
|
|
87
69
|
// that are not explicitly provided with a session.
|
|
@@ -108,7 +90,6 @@ export async function executeOperation<
|
|
|
108
90
|
const inTransaction = !!session?.inTransaction();
|
|
109
91
|
|
|
110
92
|
const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);
|
|
111
|
-
const hasWriteAspect = operation.hasAspect(Aspect.WRITE_OPERATION);
|
|
112
93
|
|
|
113
94
|
if (
|
|
114
95
|
inTransaction &&
|
|
@@ -124,6 +105,73 @@ export async function executeOperation<
|
|
|
124
105
|
session.unpin();
|
|
125
106
|
}
|
|
126
107
|
|
|
108
|
+
try {
|
|
109
|
+
return await tryOperation(operation, {
|
|
110
|
+
topology,
|
|
111
|
+
session,
|
|
112
|
+
readPreference
|
|
113
|
+
});
|
|
114
|
+
} finally {
|
|
115
|
+
if (session?.owner != null && session.owner === owner) {
|
|
116
|
+
await session.endSession();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Connects a client if it has not yet been connected
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
async function autoConnect(client: MongoClient): Promise<Topology> {
|
|
126
|
+
if (client.topology == null) {
|
|
127
|
+
if (client.s.hasBeenClosed) {
|
|
128
|
+
throw new MongoNotConnectedError('Client must be connected before running operations');
|
|
129
|
+
}
|
|
130
|
+
client.s.options[Symbol.for('@@mdb.skipPingOnConnect')] = true;
|
|
131
|
+
try {
|
|
132
|
+
await client.connect();
|
|
133
|
+
if (client.topology == null) {
|
|
134
|
+
throw new MongoRuntimeError(
|
|
135
|
+
'client.connect did not create a topology but also did not throw'
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return client.topology;
|
|
139
|
+
} finally {
|
|
140
|
+
delete client.s.options[Symbol.for('@@mdb.skipPingOnConnect')];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return client.topology;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** @internal */
|
|
147
|
+
type RetryOptions = {
|
|
148
|
+
session: ClientSession | undefined;
|
|
149
|
+
readPreference: ReadPreference;
|
|
150
|
+
topology: Topology;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Executes an operation and retries as appropriate
|
|
155
|
+
* @internal
|
|
156
|
+
*
|
|
157
|
+
* @remarks
|
|
158
|
+
* Implements behaviour described in [Retryable Reads](https://github.com/mongodb/specifications/blob/master/source/retryable-reads/retryable-reads.md) and [Retryable
|
|
159
|
+
* Writes](https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md) specification
|
|
160
|
+
*
|
|
161
|
+
* This function:
|
|
162
|
+
* - performs initial server selection
|
|
163
|
+
* - attempts to execute an operation
|
|
164
|
+
* - retries the operation if it meets the criteria for a retryable read or a retryable write
|
|
165
|
+
*
|
|
166
|
+
* @typeParam T - The operation's type
|
|
167
|
+
* @typeParam TResult - The type of the operation's result, calculated from T
|
|
168
|
+
*
|
|
169
|
+
* @param operation - The operation to execute
|
|
170
|
+
* */
|
|
171
|
+
async function tryOperation<
|
|
172
|
+
T extends AbstractOperation<TResult>,
|
|
173
|
+
TResult = ResultTypeFromOperation<T>
|
|
174
|
+
>(operation: T, { topology, session, readPreference }: RetryOptions): Promise<TResult> {
|
|
127
175
|
let selector: ReadPreference | ServerSelector;
|
|
128
176
|
|
|
129
177
|
if (operation.hasAspect(Aspect.MUST_SELECT_SAME_SERVER)) {
|
|
@@ -139,30 +187,14 @@ export async function executeOperation<
|
|
|
139
187
|
selector = readPreference;
|
|
140
188
|
}
|
|
141
189
|
|
|
142
|
-
|
|
190
|
+
let server = await topology.selectServer(selector, {
|
|
143
191
|
session,
|
|
144
192
|
operationName: operation.commandName
|
|
145
193
|
});
|
|
146
194
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (!operation.hasAspect(Aspect.RETRYABLE)) {
|
|
153
|
-
// non-retryable operation, early exit
|
|
154
|
-
try {
|
|
155
|
-
return await operation.execute(server, session);
|
|
156
|
-
} finally {
|
|
157
|
-
if (session?.owner != null && session.owner === owner) {
|
|
158
|
-
try {
|
|
159
|
-
await session.endSession();
|
|
160
|
-
} catch (error) {
|
|
161
|
-
squashError(error);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
195
|
+
const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION);
|
|
196
|
+
const hasWriteAspect = operation.hasAspect(Aspect.WRITE_OPERATION);
|
|
197
|
+
const inTransaction = session?.inTransaction() ?? false;
|
|
166
198
|
|
|
167
199
|
const willRetryRead = topology.s.options.retryReads && !inTransaction && operation.canRetryRead;
|
|
168
200
|
|
|
@@ -172,105 +204,79 @@ export async function executeOperation<
|
|
|
172
204
|
supportsRetryableWrites(server) &&
|
|
173
205
|
operation.canRetryWrite;
|
|
174
206
|
|
|
175
|
-
const willRetry =
|
|
207
|
+
const willRetry =
|
|
208
|
+
operation.hasAspect(Aspect.RETRYABLE) &&
|
|
209
|
+
session != null &&
|
|
210
|
+
((hasReadAspect && willRetryRead) || (hasWriteAspect && willRetryWrite));
|
|
176
211
|
|
|
177
|
-
if (hasWriteAspect && willRetryWrite) {
|
|
212
|
+
if (hasWriteAspect && willRetryWrite && session != null) {
|
|
178
213
|
operation.options.willRetryWrite = true;
|
|
179
214
|
session.incrementTransactionNumber();
|
|
180
215
|
}
|
|
181
216
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return await retryOperation(operation, operationError, {
|
|
187
|
-
session,
|
|
188
|
-
topology,
|
|
189
|
-
selector,
|
|
190
|
-
previousServer: server.description
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
throw operationError;
|
|
194
|
-
} finally {
|
|
195
|
-
if (session?.owner != null && session.owner === owner) {
|
|
196
|
-
try {
|
|
197
|
-
await session.endSession();
|
|
198
|
-
} catch (error) {
|
|
199
|
-
squashError(error);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
217
|
+
// TODO(NODE-6231): implement infinite retry within CSOT timeout here
|
|
218
|
+
const maxTries = willRetry ? 2 : 1;
|
|
219
|
+
let previousOperationError: MongoError | undefined;
|
|
220
|
+
let previousServer: ServerDescription | undefined;
|
|
204
221
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
222
|
+
// TODO(NODE-6231): implement infinite retry within CSOT timeout here
|
|
223
|
+
for (let tries = 0; tries < maxTries; tries++) {
|
|
224
|
+
if (previousOperationError) {
|
|
225
|
+
if (hasWriteAspect && previousOperationError.code === MMAPv1_RETRY_WRITES_ERROR_CODE) {
|
|
226
|
+
throw new MongoServerError({
|
|
227
|
+
message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
|
|
228
|
+
errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
|
|
229
|
+
originalError: previousOperationError
|
|
230
|
+
});
|
|
231
|
+
}
|
|
212
232
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
TResult = ResultTypeFromOperation<T>
|
|
216
|
-
>(
|
|
217
|
-
operation: T,
|
|
218
|
-
originalError: MongoError,
|
|
219
|
-
{ session, topology, selector, previousServer }: RetryOptions
|
|
220
|
-
): Promise<TResult> {
|
|
221
|
-
const isWriteOperation = operation.hasAspect(Aspect.WRITE_OPERATION);
|
|
222
|
-
const isReadOperation = operation.hasAspect(Aspect.READ_OPERATION);
|
|
233
|
+
if (hasWriteAspect && !isRetryableWriteError(previousOperationError))
|
|
234
|
+
throw previousOperationError;
|
|
223
235
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
message: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
|
|
227
|
-
errmsg: MMAPv1_RETRY_WRITES_ERROR_MESSAGE,
|
|
228
|
-
originalError
|
|
229
|
-
});
|
|
230
|
-
}
|
|
236
|
+
if (hasReadAspect && !isRetryableReadError(previousOperationError))
|
|
237
|
+
throw previousOperationError;
|
|
231
238
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
+
if (
|
|
240
|
+
previousOperationError instanceof MongoNetworkError &&
|
|
241
|
+
operation.hasAspect(Aspect.CURSOR_CREATING) &&
|
|
242
|
+
session != null &&
|
|
243
|
+
session.isPinned &&
|
|
244
|
+
!session.inTransaction()
|
|
245
|
+
) {
|
|
246
|
+
session.unpin({ force: true, forceClear: true });
|
|
247
|
+
}
|
|
239
248
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
) {
|
|
246
|
-
// If we have a cursor and the initial command fails with a network error,
|
|
247
|
-
// we can retry it on another connection. So we need to check it back in, clear the
|
|
248
|
-
// pool for the service id, and retry again.
|
|
249
|
-
session.unpin({ force: true, forceClear: true });
|
|
250
|
-
}
|
|
249
|
+
server = await topology.selectServer(selector, {
|
|
250
|
+
session,
|
|
251
|
+
operationName: operation.commandName,
|
|
252
|
+
previousServer
|
|
253
|
+
});
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
if (hasWriteAspect && !supportsRetryableWrites(server)) {
|
|
256
|
+
throw new MongoUnexpectedServerResponseError(
|
|
257
|
+
'Selected server does not support retryable writes'
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
258
261
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
262
|
+
try {
|
|
263
|
+
return await operation.execute(server, session);
|
|
264
|
+
} catch (operationError) {
|
|
265
|
+
if (!(operationError instanceof MongoError)) throw operationError;
|
|
264
266
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
267
|
+
if (
|
|
268
|
+
previousOperationError != null &&
|
|
269
|
+
operationError.hasErrorLabel(MongoErrorLabel.NoWritesPerformed)
|
|
270
|
+
) {
|
|
271
|
+
throw previousOperationError;
|
|
272
|
+
}
|
|
273
|
+
previousServer = server.description;
|
|
274
|
+
previousOperationError = operationError;
|
|
273
275
|
}
|
|
274
|
-
throw retryError;
|
|
275
276
|
}
|
|
277
|
+
|
|
278
|
+
throw (
|
|
279
|
+
previousOperationError ??
|
|
280
|
+
new MongoRuntimeError('Tried to propagate retryability error, but no error was found.')
|
|
281
|
+
);
|
|
276
282
|
}
|
|
@@ -192,12 +192,7 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
|
|
|
192
192
|
...this.cmdBase
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
decorateWithCollation(cmd, coll, options);
|
|
198
|
-
} catch (err) {
|
|
199
|
-
return err;
|
|
200
|
-
}
|
|
195
|
+
decorateWithCollation(cmd, coll, options);
|
|
201
196
|
|
|
202
197
|
if (options.hint) {
|
|
203
198
|
// TODO: once this method becomes a CommandOperation we will have the server
|
|
@@ -214,7 +209,7 @@ export class FindAndModifyOperation extends CommandOperation<Document> {
|
|
|
214
209
|
|
|
215
210
|
// Execute the command
|
|
216
211
|
const result = await super.executeCommand(server, session, cmd);
|
|
217
|
-
return options.includeResultMetadata ? result : result.value ?? null;
|
|
212
|
+
return options.includeResultMetadata ? result : (result.value ?? null);
|
|
218
213
|
}
|
|
219
214
|
}
|
|
220
215
|
|
package/src/operations/insert.ts
CHANGED
|
@@ -5,8 +5,7 @@ import { MongoInvalidArgumentError, MongoServerError } from '../error';
|
|
|
5
5
|
import type { InferIdType } from '../mongo_types';
|
|
6
6
|
import type { Server } from '../sdam/server';
|
|
7
7
|
import type { ClientSession } from '../sessions';
|
|
8
|
-
import type
|
|
9
|
-
import { maybeAddIdToDocuments } from '../utils';
|
|
8
|
+
import { maybeAddIdToDocuments, type MongoDBNamespace } from '../utils';
|
|
10
9
|
import { WriteConcern } from '../write_concern';
|
|
11
10
|
import { BulkWriteOperation } from './bulk_write';
|
|
12
11
|
import { CommandOperation, type CommandOperationOptions } from './command';
|
|
@@ -104,9 +103,9 @@ export interface InsertManyResult<TSchema = Document> {
|
|
|
104
103
|
export class InsertManyOperation extends AbstractOperation<InsertManyResult> {
|
|
105
104
|
override options: BulkWriteOptions;
|
|
106
105
|
collection: Collection;
|
|
107
|
-
docs: Document
|
|
106
|
+
docs: ReadonlyArray<Document>;
|
|
108
107
|
|
|
109
|
-
constructor(collection: Collection, docs: Document
|
|
108
|
+
constructor(collection: Collection, docs: ReadonlyArray<Document>, options: BulkWriteOptions) {
|
|
110
109
|
super(options);
|
|
111
110
|
|
|
112
111
|
if (!Array.isArray(docs)) {
|
|
@@ -17,11 +17,6 @@ export const Aspect = {
|
|
|
17
17
|
/** @public */
|
|
18
18
|
export type Hint = string | Document;
|
|
19
19
|
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
21
|
-
export interface OperationConstructor extends Function {
|
|
22
|
-
aspects?: Set<symbol>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
20
|
/** @public */
|
|
26
21
|
export interface OperationOptions extends BSONSerializeOptions {
|
|
27
22
|
/** Specify ClientSession for this command */
|
|
@@ -63,10 +58,12 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
63
58
|
|
|
64
59
|
[kSession]: ClientSession | undefined;
|
|
65
60
|
|
|
61
|
+
static aspects?: Set<symbol>;
|
|
62
|
+
|
|
66
63
|
constructor(options: OperationOptions = {}) {
|
|
67
64
|
this.readPreference = this.hasAspect(Aspect.WRITE_OPERATION)
|
|
68
65
|
? ReadPreference.primary
|
|
69
|
-
: ReadPreference.fromOptions(options) ?? ReadPreference.primary;
|
|
66
|
+
: (ReadPreference.fromOptions(options) ?? ReadPreference.primary);
|
|
70
67
|
|
|
71
68
|
// Pull the BSON serialize options from the already-resolved options
|
|
72
69
|
this.bsonOptions = resolveBSONOptions(options);
|
|
@@ -85,7 +82,7 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
85
82
|
abstract execute(server: Server, session: ClientSession | undefined): Promise<TResult>;
|
|
86
83
|
|
|
87
84
|
hasAspect(aspect: symbol): boolean {
|
|
88
|
-
const ctor = this.constructor as
|
|
85
|
+
const ctor = this.constructor as { aspects?: Set<symbol> };
|
|
89
86
|
if (ctor.aspects == null) {
|
|
90
87
|
return false;
|
|
91
88
|
}
|
|
@@ -102,16 +99,16 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
get canRetryRead(): boolean {
|
|
105
|
-
return
|
|
102
|
+
return this.hasAspect(Aspect.RETRYABLE) && this.hasAspect(Aspect.READ_OPERATION);
|
|
106
103
|
}
|
|
107
104
|
|
|
108
105
|
get canRetryWrite(): boolean {
|
|
109
|
-
return
|
|
106
|
+
return this.hasAspect(Aspect.RETRYABLE) && this.hasAspect(Aspect.WRITE_OPERATION);
|
|
110
107
|
}
|
|
111
108
|
}
|
|
112
109
|
|
|
113
110
|
export function defineAspects(
|
|
114
|
-
operation:
|
|
111
|
+
operation: { aspects?: Set<symbol> },
|
|
115
112
|
aspects: symbol | symbol[] | Set<symbol>
|
|
116
113
|
): Set<symbol> {
|
|
117
114
|
if (!Array.isArray(aspects) && !(aspects instanceof Set)) {
|
|
@@ -8,7 +8,10 @@ import { AbstractOperation } from '../operation';
|
|
|
8
8
|
|
|
9
9
|
/** @internal */
|
|
10
10
|
export class DropSearchIndexOperation extends AbstractOperation<void> {
|
|
11
|
-
constructor(
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly collection: Collection,
|
|
13
|
+
private readonly name: string
|
|
14
|
+
) {
|
|
12
15
|
super();
|
|
13
16
|
}
|
|
14
17
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @public
|
|
3
|
+
*/
|
|
4
|
+
export interface AsyncDisposable {
|
|
5
|
+
/**
|
|
6
|
+
* @beta
|
|
7
|
+
* @experimental
|
|
8
|
+
*/
|
|
9
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*
|
|
14
|
+
* A method that wraps disposal semantics for a given resource in the class.
|
|
15
|
+
*/
|
|
16
|
+
asyncDispose(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** @internal */
|
|
20
|
+
export function configureResourceManagement(target: AsyncDisposable) {
|
|
21
|
+
Symbol.asyncDispose &&
|
|
22
|
+
Object.defineProperty(target, Symbol.asyncDispose, {
|
|
23
|
+
value: async function asyncDispose(this: AsyncDisposable) {
|
|
24
|
+
await this.asyncDispose();
|
|
25
|
+
},
|
|
26
|
+
enumerable: false,
|
|
27
|
+
configurable: true,
|
|
28
|
+
writable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @beta
|
|
34
|
+
* @experimental
|
|
35
|
+
*
|
|
36
|
+
* Attaches `Symbol.asyncDispose` methods to the MongoClient, Cursors, sessions and change streams
|
|
37
|
+
* if Symbol.asyncDispose is defined.
|
|
38
|
+
*
|
|
39
|
+
* It's usually not necessary to call this method - the driver attempts to attach these methods
|
|
40
|
+
* itself when its loaded. However, sometimes the driver may be loaded before `Symbol.asyncDispose`
|
|
41
|
+
* is defined, in which case it is necessary to call this method directly. This can happen if the
|
|
42
|
+
* application is polyfilling `Symbol.asyncDispose`.
|
|
43
|
+
*
|
|
44
|
+
* Example:
|
|
45
|
+
*
|
|
46
|
+
* ```typescript
|
|
47
|
+
* import { configureExplicitResourceManagement, MongoClient } from 'mongodb/lib/beta';
|
|
48
|
+
*
|
|
49
|
+
* Symbol.asyncDispose ??= Symbol('dispose');
|
|
50
|
+
* load();
|
|
51
|
+
*
|
|
52
|
+
* await using client = new MongoClient(...);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export function configureExplicitResourceManagement() {
|
|
56
|
+
// We must import lazily here, because there's a circular dependency between the resource management
|
|
57
|
+
// file and each resources' file. We could move `configureResourceManagement` to a separate
|
|
58
|
+
// function, but keeping all resource-management related code together seemed preferable and I chose
|
|
59
|
+
// lazy requiring of resources instead.
|
|
60
|
+
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
|
+
const { MongoClient } = require('./mongo_client');
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
64
|
+
const { ClientSession } = require('./sessions');
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
66
|
+
const { AbstractCursor } = require('./cursor/abstract_cursor');
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
68
|
+
const { ChangeStream } = require('./change_stream');
|
|
69
|
+
|
|
70
|
+
configureResourceManagement(MongoClient.prototype);
|
|
71
|
+
configureResourceManagement(ClientSession.prototype);
|
|
72
|
+
configureResourceManagement(AbstractCursor.prototype);
|
|
73
|
+
configureResourceManagement(ChangeStream.prototype);
|
|
74
|
+
}
|
package/src/sdam/monitor.ts
CHANGED
|
@@ -308,7 +308,7 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
|
|
|
308
308
|
// duration
|
|
309
309
|
const duration =
|
|
310
310
|
isAwaitable && monitor.rttPinger
|
|
311
|
-
? monitor.rttPinger.latestRtt ?? calculateDurationInMs(start)
|
|
311
|
+
? (monitor.rttPinger.latestRtt ?? calculateDurationInMs(start))
|
|
312
312
|
: calculateDurationInMs(start);
|
|
313
313
|
|
|
314
314
|
monitor.addRttSample(duration);
|
|
@@ -378,7 +378,7 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
|
|
|
378
378
|
awaited = false;
|
|
379
379
|
connection
|
|
380
380
|
.command(ns('admin.$cmd'), cmd, options)
|
|
381
|
-
|
|
381
|
+
|
|
382
382
|
.then(onHeartbeatSucceeded, onHeartbeatFailed);
|
|
383
383
|
|
|
384
384
|
return;
|
|
@@ -397,7 +397,6 @@ function checkServer(monitor: Monitor, callback: Callback<Document | null>) {
|
|
|
397
397
|
connection.destroy();
|
|
398
398
|
throw error;
|
|
399
399
|
}
|
|
400
|
-
// eslint-disable-next-line github/no-then
|
|
401
400
|
})().then(
|
|
402
401
|
connection => {
|
|
403
402
|
if (isInCloseState(monitor)) {
|
|
@@ -547,7 +546,6 @@ export class RTTPinger {
|
|
|
547
546
|
|
|
548
547
|
const connection = this.connection;
|
|
549
548
|
if (connection == null) {
|
|
550
|
-
// eslint-disable-next-line github/no-then
|
|
551
549
|
connect(this.monitor.connectOptions).then(
|
|
552
550
|
connection => {
|
|
553
551
|
this.measureAndReschedule(start, connection);
|
|
@@ -561,7 +559,7 @@ export class RTTPinger {
|
|
|
561
559
|
|
|
562
560
|
const commandName =
|
|
563
561
|
connection.serverApi?.version || connection.helloOk ? 'hello' : LEGACY_HELLO_COMMAND;
|
|
564
|
-
|
|
562
|
+
|
|
565
563
|
connection.command(ns('admin.$cmd'), { [commandName]: 1 }, undefined).then(
|
|
566
564
|
() => this.measureAndReschedule(start),
|
|
567
565
|
() => {
|
package/src/sdam/server.ts
CHANGED
|
@@ -453,7 +453,7 @@ export class Server extends TypedEventEmitter<ServerEvents> {
|
|
|
453
453
|
} else {
|
|
454
454
|
if (
|
|
455
455
|
(isRetryableWritesEnabled(this.topology) || isTransactionCommand(cmd)) &&
|
|
456
|
-
needsRetryableWriteLabel(error, maxWireVersion(this)) &&
|
|
456
|
+
needsRetryableWriteLabel(error, maxWireVersion(this), this.description.type) &&
|
|
457
457
|
!inActiveTransaction(session, cmd)
|
|
458
458
|
) {
|
|
459
459
|
error.addErrorLabel(MongoErrorLabel.RetryableWriteError);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type Document, Long, type ObjectId } from '../bson';
|
|
2
2
|
import { type MongoError, MongoRuntimeError } from '../error';
|
|
3
3
|
import { arrayStrictEqual, compareObjectId, errorStrictEqual, HostAddress, now } from '../utils';
|
|
4
|
-
import type
|
|
5
|
-
import { ServerType } from './common';
|
|
4
|
+
import { type ClusterTime, ServerType } from './common';
|
|
6
5
|
|
|
7
6
|
const WRITABLE_SERVER_TYPES = new Set<ServerType>([
|
|
8
7
|
ServerType.RSPrimary,
|
|
@@ -262,15 +261,15 @@ export function compareTopologyVersion(
|
|
|
262
261
|
typeof currentTv.counter === 'bigint'
|
|
263
262
|
? Long.fromBigInt(currentTv.counter)
|
|
264
263
|
: Long.isLong(currentTv.counter)
|
|
265
|
-
|
|
266
|
-
|
|
264
|
+
? currentTv.counter
|
|
265
|
+
: Long.fromNumber(currentTv.counter);
|
|
267
266
|
|
|
268
267
|
const newCounter =
|
|
269
268
|
typeof newTv.counter === 'bigint'
|
|
270
269
|
? Long.fromBigInt(newTv.counter)
|
|
271
270
|
: Long.isLong(newTv.counter)
|
|
272
|
-
|
|
273
|
-
|
|
271
|
+
? newTv.counter
|
|
272
|
+
: Long.fromNumber(newTv.counter);
|
|
274
273
|
|
|
275
274
|
return currentCounter.compare(newCounter);
|
|
276
275
|
}
|
package/src/sdam/srv_polling.ts
CHANGED
|
@@ -95,7 +95,6 @@ export class SrvPoller extends TypedEventEmitter<SrvPollerEvents> {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
this._timeout = setTimeout(() => {
|
|
98
|
-
// eslint-disable-next-line github/no-then
|
|
99
98
|
this._poll().then(undefined, squashError);
|
|
100
99
|
}, this.intervalMS);
|
|
101
100
|
}
|
|
@@ -117,7 +116,7 @@ export class SrvPoller extends TypedEventEmitter<SrvPollerEvents> {
|
|
|
117
116
|
|
|
118
117
|
try {
|
|
119
118
|
srvRecords = await dns.promises.resolveSrv(this.srvAddress);
|
|
120
|
-
} catch
|
|
119
|
+
} catch {
|
|
121
120
|
this.failure();
|
|
122
121
|
return;
|
|
123
122
|
}
|