Skip to content

Commit

Permalink
fix(utils): only set retryWrites to true for valid operations
Browse files Browse the repository at this point in the history
Fixes NODE-1641
  • Loading branch information
kvwalker committed Sep 7, 2018
1 parent f93a8c3 commit 3b725ef
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 40 deletions.
16 changes: 7 additions & 9 deletions lib/bulk/common.js
Expand Up @@ -4,8 +4,8 @@ const Long = require('mongodb-core').BSON.Long;
const MongoError = require('mongodb-core').MongoError;
const toError = require('../utils').toError;
const handleCallback = require('../utils').handleCallback;
const applyRetryableWrites = require('../utils').applyRetryableWrites;
const applyWriteConcern = require('../utils').applyWriteConcern;
const shallowClone = require('../utils').shallowClone;
const ObjectID = require('mongodb-core').BSON.ObjectID;
const BSON = require('mongodb-core').BSON;

Expand Down Expand Up @@ -702,13 +702,11 @@ class BulkOperationBase {
const maxWriteBatchSize =
isMaster && isMaster.maxWriteBatchSize ? isMaster.maxWriteBatchSize : 1000;

// Get the write concern
let writeConcern = applyWriteConcern(
shallowClone(options),
{ collection: collection },
options
);
writeConcern = writeConcern.writeConcern;
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, collection.s.db);
finalOptions = applyWriteConcern(finalOptions, { collection: collection }, options);
const writeConcern = finalOptions.writeConcern;

// Get the promiseLibrary
const promiseLibrary = options.promiseLibrary || Promise;
Expand Down Expand Up @@ -754,7 +752,7 @@ class BulkOperationBase {
// Topology
topology: topology,
// Options
options: options,
options: finalOptions,
// Current operation
currentOp: currentOp,
// Executed
Expand Down
47 changes: 21 additions & 26 deletions lib/operations/collection_ops.js
@@ -1,6 +1,7 @@
'use strict';

const applyWriteConcern = require('../utils').applyWriteConcern;
const applyRetryableWrites = require('../utils').applyRetryableWrites;
const checkCollectionName = require('../utils').checkCollectionName;
const Code = require('mongodb-core').BSON.Code;
const createIndexDb = require('./db_ops').createIndex;
Expand Down Expand Up @@ -97,12 +98,10 @@ function bulkWrite(coll, operations, options, callback) {
return callback(err, null);
}

// Final options for write concern
const finalOptions = applyWriteConcern(
Object.assign({}, options),
{ db: coll.s.db, collection: coll },
options
);
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);

const writeCon = finalOptions.writeConcern ? finalOptions.writeConcern : {};
const capabilities = coll.s.topology.capabilities();
Expand Down Expand Up @@ -504,8 +503,10 @@ function findAndModify(coll, query, sort, doc, options, callback) {
// No check on the documents
options.checkKeys = false;

// Get the write concern settings
const finalOptions = applyWriteConcern(options, { db: coll.s.db, collection: coll }, options);
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);

// Decorate the findAndModify command with the write Concern
if (finalOptions.writeConcern) {
Expand Down Expand Up @@ -805,12 +806,10 @@ function insertDocuments(coll, docs, options, callback) {
// Ensure we are operating on an array op docs
docs = Array.isArray(docs) ? docs : [docs];

// Get the write concern options
const finalOptions = applyWriteConcern(
Object.assign({}, options),
{ db: coll.s.db, collection: coll },
options
);
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);

// If keep going set unordered
if (finalOptions.keepGoing === true) finalOptions.ordered = false;
Expand Down Expand Up @@ -1138,12 +1137,10 @@ function removeDocuments(coll, selector, options, callback) {
// Create an empty options object if the provided one is null
options = options || {};

// Get the write concern options
const finalOptions = applyWriteConcern(
Object.assign({}, options),
{ db: coll.s.db, collection: coll },
options
);
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);

// If selector is null set empty
if (selector == null) selector = {};
Expand Down Expand Up @@ -1336,12 +1333,10 @@ function updateDocuments(coll, selector, document, options, callback) {
if (document == null || typeof document !== 'object')
return callback(toError('document must be a valid JavaScript object'));

// Get the write concern options
const finalOptions = applyWriteConcern(
Object.assign({}, options),
{ db: coll.s.db, collection: coll },
options
);
// Final options for retryable writes and write concern
let finalOptions = Object.assign({}, options);
finalOptions = applyRetryableWrites(finalOptions, coll.s.db);
finalOptions = applyWriteConcern(finalOptions, { db: coll.s.db, collection: coll }, options);

// Do we return the actual result document
// Either use override on the function, or go back to default on either the collection
Expand Down
20 changes: 15 additions & 5 deletions lib/utils.js
Expand Up @@ -441,6 +441,20 @@ const executeOperation = (topology, operation, args, options) => {
});
};

/**
* Applies retryWrites: true to a command if retryWrites is set on the command's database.
*
* @param {object} target The target command to which we will apply retryWrites.
* @param {object} db The database from which we can inherit a retryWrites value.
*/
function applyRetryableWrites(target, db) {
if (db && db.s.options.retryWrites) {
target.retryWrites = true;
}

return target;
}

/**
* Applies a write concern to a command based on well defined inheritance rules, optionally
* detecting support for the write concern in the first place.
Expand All @@ -455,11 +469,6 @@ function applyWriteConcern(target, sources, options) {
const db = sources.db;
const coll = sources.collection;

// NOTE: there is probably a much better place for this
if (db && db.s.options.retryWrites) {
target.retryWrites = true;
}

if (options.session && options.session.inTransaction()) {
// writeConcern is not allowed within a multi-statement transaction
if (target.writeConcern) {
Expand Down Expand Up @@ -701,6 +710,7 @@ module.exports = {
mergeOptionsAndWriteConcern,
translateReadPreference,
executeOperation,
applyRetryableWrites,
applyWriteConcern,
resolveReadPreference,
isPromiseLike,
Expand Down

0 comments on commit 3b725ef

Please sign in to comment.