From 3e87c8f9d556351bd0e6ead91078ded4e485ced3 Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Fri, 27 Sep 2013 17:53:06 -0700 Subject: [PATCH] finish optimistic retry code detect collision --- packages/mongo-livedata/mongo_driver.js | 16 +++++++++--- .../mongo-livedata/mongo_livedata_tests.js | 26 +++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/packages/mongo-livedata/mongo_driver.js b/packages/mongo-livedata/mongo_driver.js index e680b1cd79..f0a5bcc8df 100644 --- a/packages/mongo-livedata/mongo_driver.js +++ b/packages/mongo-livedata/mongo_driver.js @@ -373,6 +373,13 @@ var numberAffectedCallback = function (callback) { var NUM_OPTIMISTIC_TRIES = 3; +// exposed for testing +MongoConnection._isCannotChangeIdError = function (err) { + // either of these checks should work, but just to be safe... + return (err.code === 13596 || + err.err.indexOf("cannot change _id of a document") === 0); +}; + var simulateUpsertWithInsertedId = function (collection, selector, mod, isModify, options, callback) { var insertedId = options.insertedId; // must exist @@ -445,11 +452,14 @@ var simulateUpsertWithInsertedId = function (collection, selector, mod, collection.update(selector, replacementWithId, mongoOptsForInsert, numberAffectedCallback(function (err, result) { if (err) { - // XXX figure out if this is a + // figure out if this is a // "cannot change _id of document" error, and // if so, try doUpdate() again, up to 3 times. - Meteor._debug(err); - callback(err); + if (MongoConnection._isCannotChangeIdError(err)) { + doUpdate(); + } else { + callback(err); + } } else { callback(null, _.extend(result, { insertedId: insertedId })); } diff --git a/packages/mongo-livedata/mongo_livedata_tests.js b/packages/mongo-livedata/mongo_livedata_tests.js index e473b1cc0c..0f9f5da7d9 100644 --- a/packages/mongo-livedata/mongo_livedata_tests.js +++ b/packages/mongo-livedata/mongo_livedata_tests.js @@ -913,6 +913,32 @@ if (Meteor.isServer) { onComplete(); }); + Tinytest.addAsync("mongo-livedata - upsert error parse, " + idGeneration, function (test, onComplete) { + var run = test.runId(); + var coll = new Meteor.Collection("livedata_upsert_errorparse_collection_"+run, collectionOptions); + + coll.insert({_id: 'foobar'}); + var err; + try { + coll.update({_id: 'foobar'}, {_id: 'cowbar'}); + } catch (e) { + err = e; + } + test.isTrue(err); + test.isTrue(MongoInternals.Connection._isCannotChangeIdError(err)); + + try { + coll.insert({_id: 'foobar'}); + } catch (e) { + err = e; + } + test.isTrue(err); + // duplicate id error is not same as change id error + test.isFalse(MongoInternals.Connection._isCannotChangeIdError(err)); + + onComplete(); + }); + } // end Meteor.isServer _.each(Meteor.isServer ? [true, false] : [true], function (minimongo) {