mongodb 4.0.0 → 4.1.2

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.
Files changed (246) hide show
  1. package/README.md +62 -30
  2. package/lib/bson.js +1 -0
  3. package/lib/bson.js.map +1 -1
  4. package/lib/bulk/common.js +53 -30
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/bulk/ordered.js +3 -2
  7. package/lib/bulk/ordered.js.map +1 -1
  8. package/lib/bulk/unordered.js +3 -2
  9. package/lib/bulk/unordered.js.map +1 -1
  10. package/lib/change_stream.js +23 -13
  11. package/lib/change_stream.js.map +1 -1
  12. package/lib/cmap/auth/auth_provider.js +2 -1
  13. package/lib/cmap/auth/auth_provider.js.map +1 -1
  14. package/lib/cmap/auth/gssapi.js +5 -4
  15. package/lib/cmap/auth/gssapi.js.map +1 -1
  16. package/lib/cmap/auth/mongo_credentials.js +9 -5
  17. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  18. package/lib/cmap/auth/mongocr.js +2 -2
  19. package/lib/cmap/auth/mongocr.js.map +1 -1
  20. package/lib/cmap/auth/mongodb_aws.js +32 -32
  21. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  22. package/lib/cmap/auth/plain.js +1 -1
  23. package/lib/cmap/auth/plain.js.map +1 -1
  24. package/lib/cmap/auth/scram.js +15 -12
  25. package/lib/cmap/auth/scram.js.map +1 -1
  26. package/lib/cmap/auth/x509.js +2 -2
  27. package/lib/cmap/auth/x509.js.map +1 -1
  28. package/lib/cmap/command_monitoring_events.js +26 -10
  29. package/lib/cmap/command_monitoring_events.js.map +1 -1
  30. package/lib/cmap/commands.js +9 -5
  31. package/lib/cmap/commands.js.map +1 -1
  32. package/lib/cmap/connect.js +23 -9
  33. package/lib/cmap/connect.js.map +1 -1
  34. package/lib/cmap/connection.js +43 -46
  35. package/lib/cmap/connection.js.map +1 -1
  36. package/lib/cmap/connection_pool.js +113 -15
  37. package/lib/cmap/connection_pool.js.map +1 -1
  38. package/lib/cmap/connection_pool_events.js +3 -1
  39. package/lib/cmap/connection_pool_events.js.map +1 -1
  40. package/lib/cmap/errors.js +3 -3
  41. package/lib/cmap/errors.js.map +1 -1
  42. package/lib/cmap/message_stream.js +1 -1
  43. package/lib/cmap/message_stream.js.map +1 -1
  44. package/lib/cmap/metrics.js +62 -0
  45. package/lib/cmap/metrics.js.map +1 -0
  46. package/lib/cmap/stream_description.js +3 -1
  47. package/lib/cmap/stream_description.js.map +1 -1
  48. package/lib/cmap/wire_protocol/compression.js +22 -9
  49. package/lib/cmap/wire_protocol/compression.js.map +1 -1
  50. package/lib/cmap/wire_protocol/shared.js +1 -1
  51. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  52. package/lib/collection.js +23 -18
  53. package/lib/collection.js.map +1 -1
  54. package/lib/connection_string.js +76 -30
  55. package/lib/connection_string.js.map +1 -1
  56. package/lib/cursor/abstract_cursor.js +75 -68
  57. package/lib/cursor/abstract_cursor.js.map +1 -1
  58. package/lib/cursor/aggregation_cursor.js +47 -9
  59. package/lib/cursor/aggregation_cursor.js.map +1 -1
  60. package/lib/cursor/find_cursor.js +53 -13
  61. package/lib/cursor/find_cursor.js.map +1 -1
  62. package/lib/db.js +21 -14
  63. package/lib/db.js.map +1 -1
  64. package/lib/deps.js +16 -5
  65. package/lib/deps.js.map +1 -1
  66. package/lib/encrypter.js +5 -8
  67. package/lib/encrypter.js.map +1 -1
  68. package/lib/error.js +230 -34
  69. package/lib/error.js.map +1 -1
  70. package/lib/explain.js +2 -2
  71. package/lib/explain.js.map +1 -1
  72. package/lib/gridfs/download.js +22 -47
  73. package/lib/gridfs/download.js.map +1 -1
  74. package/lib/gridfs/index.js +4 -3
  75. package/lib/gridfs/index.js.map +1 -1
  76. package/lib/gridfs/upload.js +13 -21
  77. package/lib/gridfs/upload.js.map +1 -1
  78. package/lib/index.js +27 -2
  79. package/lib/index.js.map +1 -1
  80. package/lib/logger.js +3 -2
  81. package/lib/logger.js.map +1 -1
  82. package/lib/mongo_client.js +5 -8
  83. package/lib/mongo_client.js.map +1 -1
  84. package/lib/mongo_types.js.map +1 -1
  85. package/lib/operations/add_user.js +2 -3
  86. package/lib/operations/add_user.js.map +1 -1
  87. package/lib/operations/aggregate.js +12 -9
  88. package/lib/operations/aggregate.js.map +1 -1
  89. package/lib/operations/command.js +5 -7
  90. package/lib/operations/command.js.map +1 -1
  91. package/lib/operations/common_functions.js +1 -1
  92. package/lib/operations/common_functions.js.map +1 -1
  93. package/lib/operations/connect.js +3 -2
  94. package/lib/operations/connect.js.map +1 -1
  95. package/lib/operations/count.js +1 -1
  96. package/lib/operations/count.js.map +1 -1
  97. package/lib/operations/count_documents.js +1 -1
  98. package/lib/operations/count_documents.js.map +1 -1
  99. package/lib/operations/delete.js +5 -5
  100. package/lib/operations/delete.js.map +1 -1
  101. package/lib/operations/distinct.js +2 -2
  102. package/lib/operations/distinct.js.map +1 -1
  103. package/lib/operations/estimated_document_count.js +5 -1
  104. package/lib/operations/estimated_document_count.js.map +1 -1
  105. package/lib/operations/eval.js.map +1 -1
  106. package/lib/operations/execute_operation.js +31 -17
  107. package/lib/operations/execute_operation.js.map +1 -1
  108. package/lib/operations/find.js +13 -9
  109. package/lib/operations/find.js.map +1 -1
  110. package/lib/operations/find_and_modify.js +9 -9
  111. package/lib/operations/find_and_modify.js.map +1 -1
  112. package/lib/operations/indexes.js +8 -3
  113. package/lib/operations/indexes.js.map +1 -1
  114. package/lib/operations/insert.js +5 -3
  115. package/lib/operations/insert.js.map +1 -1
  116. package/lib/operations/is_capped.js +2 -1
  117. package/lib/operations/is_capped.js.map +1 -1
  118. package/lib/operations/list_collections.js +6 -3
  119. package/lib/operations/list_collections.js.map +1 -1
  120. package/lib/operations/map_reduce.js +1 -1
  121. package/lib/operations/map_reduce.js.map +1 -1
  122. package/lib/operations/operation.js +3 -1
  123. package/lib/operations/operation.js.map +1 -1
  124. package/lib/operations/options_operation.js +2 -1
  125. package/lib/operations/options_operation.js.map +1 -1
  126. package/lib/operations/profiling_level.js +4 -2
  127. package/lib/operations/profiling_level.js.map +1 -1
  128. package/lib/operations/set_profiling_level.js +4 -2
  129. package/lib/operations/set_profiling_level.js.map +1 -1
  130. package/lib/operations/update.js +12 -12
  131. package/lib/operations/update.js.map +1 -1
  132. package/lib/operations/validate_collection.js +6 -5
  133. package/lib/operations/validate_collection.js.map +1 -1
  134. package/lib/promise_provider.js +1 -1
  135. package/lib/promise_provider.js.map +1 -1
  136. package/lib/read_preference.js +8 -8
  137. package/lib/read_preference.js.map +1 -1
  138. package/lib/sdam/common.js +12 -10
  139. package/lib/sdam/common.js.map +1 -1
  140. package/lib/sdam/server.js +90 -25
  141. package/lib/sdam/server.js.map +1 -1
  142. package/lib/sdam/server_description.js +9 -4
  143. package/lib/sdam/server_description.js.map +1 -1
  144. package/lib/sdam/server_selection.js +10 -4
  145. package/lib/sdam/server_selection.js.map +1 -1
  146. package/lib/sdam/srv_polling.js +1 -1
  147. package/lib/sdam/srv_polling.js.map +1 -1
  148. package/lib/sdam/topology.js +42 -21
  149. package/lib/sdam/topology.js.map +1 -1
  150. package/lib/sdam/topology_description.js +7 -3
  151. package/lib/sdam/topology_description.js.map +1 -1
  152. package/lib/sessions.js +132 -31
  153. package/lib/sessions.js.map +1 -1
  154. package/lib/sort.js +3 -3
  155. package/lib/sort.js.map +1 -1
  156. package/lib/transactions.js +15 -7
  157. package/lib/transactions.js.map +1 -1
  158. package/lib/utils.js +60 -20
  159. package/lib/utils.js.map +1 -1
  160. package/mongodb.d.ts +523 -138
  161. package/mongodb.ts34.d.ts +480 -141
  162. package/package.json +44 -48
  163. package/src/bson.ts +1 -0
  164. package/src/bulk/common.ts +83 -43
  165. package/src/bulk/ordered.ts +4 -3
  166. package/src/bulk/unordered.ts +4 -3
  167. package/src/change_stream.ts +46 -29
  168. package/src/cmap/auth/auth_provider.ts +3 -2
  169. package/src/cmap/auth/gssapi.ts +15 -5
  170. package/src/cmap/auth/mongo_credentials.ts +22 -8
  171. package/src/cmap/auth/mongocr.ts +3 -3
  172. package/src/cmap/auth/mongodb_aws.ts +52 -39
  173. package/src/cmap/auth/plain.ts +2 -2
  174. package/src/cmap/auth/scram.ts +23 -13
  175. package/src/cmap/auth/x509.ts +3 -3
  176. package/src/cmap/command_monitoring_events.ts +36 -14
  177. package/src/cmap/commands.ts +12 -6
  178. package/src/cmap/connect.ts +42 -12
  179. package/src/cmap/connection.ts +54 -62
  180. package/src/cmap/connection_pool.ts +141 -20
  181. package/src/cmap/connection_pool_events.ts +8 -1
  182. package/src/cmap/errors.ts +3 -4
  183. package/src/cmap/message_stream.ts +2 -4
  184. package/src/cmap/metrics.ts +58 -0
  185. package/src/cmap/stream_description.ts +6 -1
  186. package/src/cmap/wire_protocol/compression.ts +26 -13
  187. package/src/cmap/wire_protocol/shared.ts +4 -2
  188. package/src/collection.ts +75 -70
  189. package/src/connection_string.ts +97 -34
  190. package/src/cursor/abstract_cursor.ts +141 -104
  191. package/src/cursor/aggregation_cursor.ts +34 -20
  192. package/src/cursor/find_cursor.ts +41 -21
  193. package/src/db.ts +19 -18
  194. package/src/deps.ts +110 -22
  195. package/src/encrypter.ts +6 -12
  196. package/src/error.ts +264 -48
  197. package/src/explain.ts +3 -3
  198. package/src/gridfs/download.ts +48 -53
  199. package/src/gridfs/index.ts +5 -4
  200. package/src/gridfs/upload.ts +32 -33
  201. package/src/index.ts +42 -4
  202. package/src/logger.ts +6 -3
  203. package/src/mongo_client.ts +20 -23
  204. package/src/mongo_types.ts +19 -20
  205. package/src/operations/add_user.ts +4 -5
  206. package/src/operations/aggregate.ts +18 -17
  207. package/src/operations/command.ts +7 -10
  208. package/src/operations/common_functions.ts +2 -3
  209. package/src/operations/connect.ts +4 -3
  210. package/src/operations/count.ts +2 -2
  211. package/src/operations/count_documents.ts +2 -2
  212. package/src/operations/delete.ts +8 -6
  213. package/src/operations/distinct.ts +5 -3
  214. package/src/operations/estimated_document_count.ts +5 -1
  215. package/src/operations/eval.ts +1 -1
  216. package/src/operations/execute_operation.ts +41 -20
  217. package/src/operations/find.ts +25 -16
  218. package/src/operations/find_and_modify.ts +12 -10
  219. package/src/operations/indexes.ts +39 -8
  220. package/src/operations/insert.ts +7 -4
  221. package/src/operations/is_capped.ts +3 -2
  222. package/src/operations/list_collections.ts +9 -6
  223. package/src/operations/map_reduce.ts +4 -2
  224. package/src/operations/operation.ts +7 -2
  225. package/src/operations/options_operation.ts +3 -2
  226. package/src/operations/profiling_level.ts +5 -3
  227. package/src/operations/set_profiling_level.ts +9 -3
  228. package/src/operations/update.ts +17 -13
  229. package/src/operations/validate_collection.ts +7 -6
  230. package/src/promise_provider.ts +2 -2
  231. package/src/read_preference.ts +11 -9
  232. package/src/sdam/common.ts +11 -9
  233. package/src/sdam/server.ts +168 -69
  234. package/src/sdam/server_description.ts +16 -4
  235. package/src/sdam/server_selection.ts +15 -7
  236. package/src/sdam/srv_polling.ts +2 -2
  237. package/src/sdam/topology.ts +67 -36
  238. package/src/sdam/topology_description.ts +11 -4
  239. package/src/sessions.ts +194 -37
  240. package/src/sort.ts +6 -4
  241. package/src/transactions.ts +18 -9
  242. package/src/utils.ts +73 -20
  243. package/HISTORY.md +0 -2993
  244. package/lib/operations/find_one.js +0 -34
  245. package/lib/operations/find_one.js.map +0 -1
  246. package/src/operations/find_one.ts +0 -43
@@ -17,7 +17,8 @@ export const TopologyType = Object.freeze({
17
17
  ReplicaSetNoPrimary: 'ReplicaSetNoPrimary',
18
18
  ReplicaSetWithPrimary: 'ReplicaSetWithPrimary',
19
19
  Sharded: 'Sharded',
20
- Unknown: 'Unknown'
20
+ Unknown: 'Unknown',
21
+ LoadBalanced: 'LoadBalanced'
21
22
  } as const);
22
23
 
23
24
  /** @public */
@@ -36,7 +37,8 @@ export const ServerType = Object.freeze({
36
37
  RSArbiter: 'RSArbiter',
37
38
  RSOther: 'RSOther',
38
39
  RSGhost: 'RSGhost',
39
- Unknown: 'Unknown'
40
+ Unknown: 'Unknown',
41
+ LoadBalancer: 'LoadBalancer'
40
42
  } as const);
41
43
 
42
44
  /** @public */
@@ -66,16 +68,16 @@ export interface ClusterTime {
66
68
  };
67
69
  }
68
70
 
69
- /** Shared function to determine clusterTime for a given topology */
70
- export function resolveClusterTime(
71
- topology: Topology | ClientSession,
71
+ /** Shared function to determine clusterTime for a given topology or session */
72
+ export function _advanceClusterTime(
73
+ entity: Topology | ClientSession,
72
74
  $clusterTime: ClusterTime
73
75
  ): void {
74
- if (topology.clusterTime == null) {
75
- topology.clusterTime = $clusterTime;
76
+ if (entity.clusterTime == null) {
77
+ entity.clusterTime = $clusterTime;
76
78
  } else {
77
- if ($clusterTime.clusterTime.greaterThan(topology.clusterTime.clusterTime)) {
78
- topology.clusterTime = $clusterTime;
79
+ if ($clusterTime.clusterTime.greaterThan(entity.clusterTime.clusterTime)) {
80
+ entity.clusterTime = $clusterTime;
79
81
  }
80
82
  }
81
83
  }
@@ -18,12 +18,12 @@ import {
18
18
  EventEmitterWithState
19
19
  } from '../utils';
20
20
  import {
21
- ServerType,
22
21
  STATE_CLOSED,
23
22
  STATE_CLOSING,
24
23
  STATE_CONNECTING,
25
24
  STATE_CONNECTED,
26
- ClusterTime
25
+ ClusterTime,
26
+ TopologyType
27
27
  } from './common';
28
28
  import {
29
29
  MongoError,
@@ -33,7 +33,9 @@ import {
33
33
  isRetryableWriteError,
34
34
  isNodeShuttingDownError,
35
35
  isNetworkErrorBeforeHandshake,
36
- MongoDriverError
36
+ MongoCompatibilityError,
37
+ MongoInvalidArgumentError,
38
+ MongoServerClosedError
37
39
  } from '../error';
38
40
  import {
39
41
  Connection,
@@ -54,6 +56,7 @@ import type { Document, Long } from '../bson';
54
56
  import type { AutoEncrypter } from '../deps';
55
57
  import type { ServerApi } from '../mongo_client';
56
58
  import { TypedEventEmitter } from '../mongo_types';
59
+ import { supportsRetryableWrites } from '../utils';
57
60
 
58
61
  const stateTransition = makeStateMachine({
59
62
  [STATE_CLOSED]: [STATE_CLOSED, STATE_CONNECTING],
@@ -151,6 +154,9 @@ export class Server extends TypedEventEmitter<ServerEvents> {
151
154
  this.clusterTime = clusterTime;
152
155
  });
153
156
 
157
+ // monitoring is disabled in load balancing mode
158
+ if (this.loadBalanced) return;
159
+
154
160
  // create the monitor
155
161
  this[kMonitor] = new Monitor(this, this.s.options);
156
162
 
@@ -192,6 +198,10 @@ export class Server extends TypedEventEmitter<ServerEvents> {
192
198
  }
193
199
  }
194
200
 
201
+ get loadBalanced(): boolean {
202
+ return this.s.topology.description.type === TopologyType.LoadBalanced;
203
+ }
204
+
195
205
  /**
196
206
  * Initiate server connect
197
207
  */
@@ -201,7 +211,16 @@ export class Server extends TypedEventEmitter<ServerEvents> {
201
211
  }
202
212
 
203
213
  stateTransition(this, STATE_CONNECTING);
204
- this[kMonitor].connect();
214
+
215
+ // If in load balancer mode we automatically set the server to
216
+ // a load balancer. It never transitions out of this state and
217
+ // has no monitor.
218
+ if (!this.loadBalanced) {
219
+ this[kMonitor].connect();
220
+ } else {
221
+ stateTransition(this, STATE_CONNECTED);
222
+ this.emit(Server.CONNECT, this);
223
+ }
205
224
  }
206
225
 
207
226
  /** Destroy the server connection */
@@ -219,7 +238,10 @@ export class Server extends TypedEventEmitter<ServerEvents> {
219
238
 
220
239
  stateTransition(this, STATE_CLOSING);
221
240
 
222
- this[kMonitor].close();
241
+ if (!this.loadBalanced) {
242
+ this[kMonitor].close();
243
+ }
244
+
223
245
  this.s.pool.close(options, err => {
224
246
  stateTransition(this, STATE_CLOSED);
225
247
  this.emit('closed');
@@ -234,7 +256,9 @@ export class Server extends TypedEventEmitter<ServerEvents> {
234
256
  * this will be a no-op.
235
257
  */
236
258
  requestCheck(): void {
237
- this[kMonitor].requestCheck();
259
+ if (!this.loadBalanced) {
260
+ this[kMonitor].requestCheck();
261
+ }
238
262
  }
239
263
 
240
264
  /**
@@ -260,15 +284,15 @@ export class Server extends TypedEventEmitter<ServerEvents> {
260
284
  }
261
285
 
262
286
  if (callback == null) {
263
- throw new MongoDriverError('callback must be provided');
287
+ throw new MongoInvalidArgumentError('Callback must be provided');
264
288
  }
265
289
 
266
290
  if (ns.db == null || typeof ns === 'string') {
267
- throw new MongoDriverError('ns must not be a string');
291
+ throw new MongoInvalidArgumentError('Namespace must not be a string');
268
292
  }
269
293
 
270
294
  if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
271
- callback(new MongoDriverError('server is closed'));
295
+ callback(new MongoServerClosedError());
272
296
  return;
273
297
  }
274
298
 
@@ -277,23 +301,47 @@ export class Server extends TypedEventEmitter<ServerEvents> {
277
301
 
278
302
  // error if collation not supported
279
303
  if (collationNotSupported(this, cmd)) {
280
- callback(new MongoDriverError(`server ${this.name} does not support collation`));
304
+ callback(new MongoCompatibilityError(`Server ${this.name} does not support collation`));
281
305
  return;
282
306
  }
283
307
 
284
- this.s.pool.withConnection((err, conn, cb) => {
285
- if (err || !conn) {
286
- markServerUnknown(this, err);
287
- return cb(err);
288
- }
308
+ const session = finalOptions.session;
309
+ const conn = session?.pinnedConnection;
310
+
311
+ // NOTE: This is a hack! We can't retrieve the connections used for executing an operation
312
+ // (and prevent them from being checked back in) at the point of operation execution.
313
+ // This should be considered as part of the work for NODE-2882
314
+ if (this.loadBalanced && session && conn == null && isPinnableCommand(cmd, session)) {
315
+ this.s.pool.checkOut((err, checkedOut) => {
316
+ if (err || checkedOut == null) {
317
+ if (callback) return callback(err);
318
+ return;
319
+ }
289
320
 
290
- conn.command(
291
- ns,
292
- cmd,
293
- finalOptions,
294
- makeOperationHandler(this, conn, cmd, finalOptions, cb) as Callback<Document>
295
- );
296
- }, callback);
321
+ session.pin(checkedOut);
322
+ this.command(ns, cmd, finalOptions, callback as Callback<Document>);
323
+ });
324
+
325
+ return;
326
+ }
327
+
328
+ this.s.pool.withConnection(
329
+ conn,
330
+ (err, conn, cb) => {
331
+ if (err || !conn) {
332
+ markServerUnknown(this, err);
333
+ return cb(err);
334
+ }
335
+
336
+ conn.command(
337
+ ns,
338
+ cmd,
339
+ finalOptions,
340
+ makeOperationHandler(this, conn, cmd, finalOptions, cb) as Callback<Document>
341
+ );
342
+ },
343
+ callback
344
+ );
297
345
  }
298
346
 
299
347
  /**
@@ -302,18 +350,27 @@ export class Server extends TypedEventEmitter<ServerEvents> {
302
350
  */
303
351
  query(ns: MongoDBNamespace, cmd: Document, options: QueryOptions, callback: Callback): void {
304
352
  if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
305
- callback(new MongoDriverError('server is closed'));
353
+ callback(new MongoServerClosedError());
306
354
  return;
307
355
  }
308
356
 
309
- this.s.pool.withConnection((err, conn, cb) => {
310
- if (err || !conn) {
311
- markServerUnknown(this, err);
312
- return cb(err);
313
- }
357
+ this.s.pool.withConnection(
358
+ undefined,
359
+ (err, conn, cb) => {
360
+ if (err || !conn) {
361
+ markServerUnknown(this, err);
362
+ return cb(err);
363
+ }
314
364
 
315
- conn.query(ns, cmd, options, makeOperationHandler(this, conn, cmd, options, cb) as Callback);
316
- }, callback);
365
+ conn.query(
366
+ ns,
367
+ cmd,
368
+ options,
369
+ makeOperationHandler(this, conn, cmd, options, cb) as Callback
370
+ );
371
+ },
372
+ callback
373
+ );
317
374
  }
318
375
 
319
376
  /**
@@ -327,23 +384,27 @@ export class Server extends TypedEventEmitter<ServerEvents> {
327
384
  callback: Callback<Document>
328
385
  ): void {
329
386
  if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
330
- callback(new MongoDriverError('server is closed'));
387
+ callback(new MongoServerClosedError());
331
388
  return;
332
389
  }
333
390
 
334
- this.s.pool.withConnection((err, conn, cb) => {
335
- if (err || !conn) {
336
- markServerUnknown(this, err);
337
- return cb(err);
338
- }
391
+ this.s.pool.withConnection(
392
+ options.session?.pinnedConnection,
393
+ (err, conn, cb) => {
394
+ if (err || !conn) {
395
+ markServerUnknown(this, err);
396
+ return cb(err);
397
+ }
339
398
 
340
- conn.getMore(
341
- ns,
342
- cursorId,
343
- options,
344
- makeOperationHandler(this, conn, {}, options, cb) as Callback
345
- );
346
- }, callback);
399
+ conn.getMore(
400
+ ns,
401
+ cursorId,
402
+ options,
403
+ makeOperationHandler(this, conn, {}, options, cb) as Callback
404
+ );
405
+ },
406
+ callback
407
+ );
347
408
  }
348
409
 
349
410
  /**
@@ -358,25 +419,29 @@ export class Server extends TypedEventEmitter<ServerEvents> {
358
419
  ): void {
359
420
  if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
360
421
  if (typeof callback === 'function') {
361
- callback(new MongoDriverError('server is closed'));
422
+ callback(new MongoServerClosedError());
362
423
  }
363
424
 
364
425
  return;
365
426
  }
366
427
 
367
- this.s.pool.withConnection((err, conn, cb) => {
368
- if (err || !conn) {
369
- markServerUnknown(this, err);
370
- return cb(err);
371
- }
428
+ this.s.pool.withConnection(
429
+ options.session?.pinnedConnection,
430
+ (err, conn, cb) => {
431
+ if (err || !conn) {
432
+ markServerUnknown(this, err);
433
+ return cb(err);
434
+ }
372
435
 
373
- conn.killCursors(
374
- ns,
375
- cursorIds,
376
- options,
377
- makeOperationHandler(this, conn, {}, undefined, cb) as Callback
378
- );
379
- }, callback);
436
+ conn.killCursors(
437
+ ns,
438
+ cursorIds,
439
+ options,
440
+ makeOperationHandler(this, conn, {}, undefined, cb) as Callback
441
+ );
442
+ },
443
+ callback
444
+ );
380
445
  }
381
446
  }
382
447
 
@@ -395,14 +460,6 @@ Object.defineProperty(Server.prototype, 'clusterTime', {
395
460
  }
396
461
  });
397
462
 
398
- function supportsRetryableWrites(server: Server) {
399
- return (
400
- server.description.maxWireVersion >= 6 &&
401
- server.description.logicalSessionTimeoutMinutes &&
402
- server.description.type !== ServerType.Standalone
403
- );
404
- }
405
-
406
463
  function calculateRoundTripTime(oldRtt: number, duration: number): number {
407
464
  if (oldRtt === -1) {
408
465
  return duration;
@@ -413,6 +470,11 @@ function calculateRoundTripTime(oldRtt: number, duration: number): number {
413
470
  }
414
471
 
415
472
  function markServerUnknown(server: Server, error?: MongoError) {
473
+ // Load balancer servers can never be marked unknown.
474
+ if (server.loadBalanced) {
475
+ return;
476
+ }
477
+
416
478
  if (error instanceof MongoNetworkError && !(error instanceof MongoNetworkTimeoutError)) {
417
479
  server[kMonitor].reset();
418
480
  }
@@ -427,7 +489,28 @@ function markServerUnknown(server: Server, error?: MongoError) {
427
489
  );
428
490
  }
429
491
 
492
+ function isPinnableCommand(cmd: Document, session?: ClientSession): boolean {
493
+ if (session) {
494
+ return (
495
+ session.inTransaction() ||
496
+ 'aggregate' in cmd ||
497
+ 'find' in cmd ||
498
+ 'getMore' in cmd ||
499
+ 'listCollections' in cmd ||
500
+ 'listIndexes' in cmd
501
+ );
502
+ }
503
+
504
+ return false;
505
+ }
506
+
430
507
  function connectionIsStale(pool: ConnectionPool, connection: Connection) {
508
+ if (connection.serviceId) {
509
+ return (
510
+ connection.generation !== pool.serviceGenerations.get(connection.serviceId.toHexString())
511
+ );
512
+ }
513
+
431
514
  return connection.generation !== pool.generation;
432
515
  }
433
516
 
@@ -462,6 +545,11 @@ function makeOperationHandler(
462
545
  session.serverSession.isDirty = true;
463
546
  }
464
547
 
548
+ // inActiveTransaction check handles commit and abort.
549
+ if (inActiveTransaction(session, cmd) && !err.hasErrorLabel('TransientTransactionError')) {
550
+ err.addErrorLabel('TransientTransactionError');
551
+ }
552
+
465
553
  if (
466
554
  (isRetryableWritesEnabled(server.s.topology) || isTransactionCommand(cmd)) &&
467
555
  supportsRetryableWrites(server) &&
@@ -471,8 +559,13 @@ function makeOperationHandler(
471
559
  }
472
560
 
473
561
  if (!(err instanceof MongoNetworkTimeoutError) || isNetworkErrorBeforeHandshake(err)) {
474
- markServerUnknown(server, err);
475
- server.s.pool.clear();
562
+ // In load balanced mode we never mark the server as unknown and always
563
+ // clear for the specific service id.
564
+
565
+ server.s.pool.clear(connection.serviceId);
566
+ if (!server.loadBalanced) {
567
+ markServerUnknown(server, err);
568
+ }
476
569
  }
477
570
  } else {
478
571
  // if pre-4.4 server, then add error label if its a retryable write error
@@ -488,14 +581,20 @@ function makeOperationHandler(
488
581
  if (isSDAMUnrecoverableError(err)) {
489
582
  if (shouldHandleStateChangeError(server, err)) {
490
583
  if (maxWireVersion(server) <= 7 || isNodeShuttingDownError(err)) {
491
- server.s.pool.clear();
584
+ server.s.pool.clear(connection.serviceId);
492
585
  }
493
586
 
494
- markServerUnknown(server, err);
495
- process.nextTick(() => server.requestCheck());
587
+ if (!server.loadBalanced) {
588
+ markServerUnknown(server, err);
589
+ process.nextTick(() => server.requestCheck());
590
+ }
496
591
  }
497
592
  }
498
593
  }
594
+
595
+ if (session && session.isPinned && err.hasErrorLabel('TransientTransactionError')) {
596
+ session.unpin({ force: true });
597
+ }
499
598
  }
500
599
 
501
600
  callback(err, result);
@@ -7,14 +7,16 @@ import type { MongoError } from '../error';
7
7
  const WRITABLE_SERVER_TYPES = new Set<ServerType>([
8
8
  ServerType.RSPrimary,
9
9
  ServerType.Standalone,
10
- ServerType.Mongos
10
+ ServerType.Mongos,
11
+ ServerType.LoadBalancer
11
12
  ]);
12
13
 
13
14
  const DATA_BEARING_SERVER_TYPES = new Set<ServerType>([
14
15
  ServerType.RSPrimary,
15
16
  ServerType.RSSecondary,
16
17
  ServerType.Mongos,
17
- ServerType.Standalone
18
+ ServerType.Standalone,
19
+ ServerType.LoadBalancer
18
20
  ]);
19
21
 
20
22
  /** @public */
@@ -36,6 +38,9 @@ export interface ServerDescriptionOptions {
36
38
 
37
39
  /** The topologyVersion */
38
40
  topologyVersion?: TopologyVersion;
41
+
42
+ /** If the client is in load balancing mode. */
43
+ loadBalanced?: boolean;
39
44
  }
40
45
 
41
46
  /**
@@ -90,7 +95,7 @@ export class ServerDescription {
90
95
  this._hostAddress = address;
91
96
  this.address = this._hostAddress.toString();
92
97
  }
93
- this.type = parseServerType(ismaster);
98
+ this.type = parseServerType(ismaster, options);
94
99
  this.hosts = ismaster?.hosts?.map((host: string) => host.toLowerCase()) ?? [];
95
100
  this.passives = ismaster?.passives?.map((host: string) => host.toLowerCase()) ?? [];
96
101
  this.arbiters = ismaster?.arbiters?.map((host: string) => host.toLowerCase()) ?? [];
@@ -206,7 +211,14 @@ export class ServerDescription {
206
211
  }
207
212
 
208
213
  // Parses an `ismaster` message and determines the server type
209
- export function parseServerType(ismaster?: Document): ServerType {
214
+ export function parseServerType(
215
+ ismaster?: Document,
216
+ options?: ServerDescriptionOptions
217
+ ): ServerType {
218
+ if (options?.loadBalanced) {
219
+ return ServerType.LoadBalancer;
220
+ }
221
+
210
222
  if (!ismaster || !ismaster.ok) {
211
223
  return ServerType.Unknown;
212
224
  }
@@ -1,6 +1,6 @@
1
1
  import { ServerType, TopologyType } from './common';
2
2
  import { ReadPreference } from '../read_preference';
3
- import { MongoDriverError } from '../error';
3
+ import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error';
4
4
  import type { TopologyDescription } from './topology_description';
5
5
  import type { ServerDescription, TagSet } from './server_description';
6
6
 
@@ -50,14 +50,14 @@ function maxStalenessReducer(
50
50
  const maxStalenessVariance =
51
51
  (topologyDescription.heartbeatFrequencyMS + IDLE_WRITE_PERIOD) / 1000;
52
52
  if (maxStaleness < maxStalenessVariance) {
53
- throw new MongoDriverError(
54
- `maxStalenessSeconds must be at least ${maxStalenessVariance} seconds`
53
+ throw new MongoInvalidArgumentError(
54
+ `Option "maxStalenessSeconds" must be at least ${maxStalenessVariance} seconds`
55
55
  );
56
56
  }
57
57
 
58
58
  if (maxStaleness < SMALLEST_MAX_STALENESS_SECONDS) {
59
- throw new MongoDriverError(
60
- `maxStalenessSeconds must be at least ${SMALLEST_MAX_STALENESS_SECONDS} seconds`
59
+ throw new MongoInvalidArgumentError(
60
+ `Option "maxStalenessSeconds" must be at least ${SMALLEST_MAX_STALENESS_SECONDS} seconds`
61
61
  );
62
62
  }
63
63
 
@@ -207,6 +207,10 @@ function knownFilter(server: ServerDescription): boolean {
207
207
  return server.type !== ServerType.Unknown;
208
208
  }
209
209
 
210
+ function loadBalancerFilter(server: ServerDescription): boolean {
211
+ return server.type === ServerType.LoadBalancer;
212
+ }
213
+
210
214
  /**
211
215
  * Returns a function which selects servers based on a provided read preference
212
216
  *
@@ -214,7 +218,7 @@ function knownFilter(server: ServerDescription): boolean {
214
218
  */
215
219
  export function readPreferenceServerSelector(readPreference: ReadPreference): ServerSelector {
216
220
  if (!readPreference.isValid()) {
217
- throw new MongoDriverError('Invalid read preference specified');
221
+ throw new MongoInvalidArgumentError('Invalid read preference specified');
218
222
  }
219
223
 
220
224
  return (
@@ -227,11 +231,15 @@ export function readPreferenceServerSelector(readPreference: ReadPreference): Se
227
231
  readPreference.minWireVersion &&
228
232
  readPreference.minWireVersion > commonWireVersion
229
233
  ) {
230
- throw new MongoDriverError(
234
+ throw new MongoCompatibilityError(
231
235
  `Minimum wire version '${readPreference.minWireVersion}' required, but found '${commonWireVersion}'`
232
236
  );
233
237
  }
234
238
 
239
+ if (topologyDescription.type === TopologyType.LoadBalanced) {
240
+ return servers.filter(loadBalancerFilter);
241
+ }
242
+
235
243
  if (topologyDescription.type === TopologyType.Unknown) {
236
244
  return [];
237
245
  }
@@ -2,7 +2,7 @@ import * as dns from 'dns';
2
2
  import { Logger, LoggerOptions } from '../logger';
3
3
  import { HostAddress } from '../utils';
4
4
  import { TypedEventEmitter } from '../mongo_types';
5
- import { MongoDriverError } from '../error';
5
+ import { MongoRuntimeError } from '../error';
6
6
 
7
7
  /**
8
8
  * Determines whether a provided address matches the provided parent domain in order
@@ -67,7 +67,7 @@ export class SrvPoller extends TypedEventEmitter<SrvPollerEvents> {
67
67
  super();
68
68
 
69
69
  if (!options || !options.srvHost) {
70
- throw new MongoDriverError('options for SrvPoller must exist and include srvHost');
70
+ throw new MongoRuntimeError('Options for SrvPoller must exist and include srvHost');
71
71
  }
72
72
 
73
73
  this.srvHost = options.srvHost;