Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-16359

Upserting a document where the _id field is a regex can cause secondaries to crash

    • Type: Icon: Bug Bug
    • Resolution: Duplicate
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 2.4.6, 2.4.12
    • Component/s: Replication, Stability
    • None
    • ALL
    • Hide

      MongoDB 2.4.12:

      > rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) })
      0 : PRIMARY
      1 : SECONDARY
      2 : SECONDARY
      replset:PRIMARY>
      replset:PRIMARY> var date1 = new ISODate("2013-01-01T00:00:00Z");
      replset:PRIMARY> var date2 = new ISODate("2014-01-01T00:00:00Z");
      replset:PRIMARY> var date3 = new ISODate("2015-01-01T00:00:00Z");
      replset:PRIMARY>
      replset:PRIMARY> db.foo.insert({_id: "ABC", when: date1})
      replset:PRIMARY> db.foo.update({
      ...    _id: /[A-Z]/,
      ...    when: { $gte: date2 },
      ... },{
      ...    $set:{ when: date3 }
      ... },{
      ...    multi: true, upsert: true
      ... });
      replset:PRIMARY>
      replset:PRIMARY>
      Mon Dec  1 11:39:28.030 DBClientCursor::init call() failed
      >
      Mon Dec  1 11:39:29.166 trying reconnect to 127.0.0.1:27017
      Mon Dec  1 11:39:29.167 reconnect 127.0.0.1:27017 ok
      replset:SECONDARY>
      replset:SECONDARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) })
      0 : SECONDARY
      1 : (not reachable/healthy)
      2 : (not reachable/healthy)
      replset:SECONDARY>
      replset:SECONDARY> rs.slaveOk()
      replset:SECONDARY> db.foo.find()
      { "_id" : "ABC", "when" : ISODate("2013-01-01T00:00:00Z") }
      { "_id" : /[A-Z]/, "when" : ISODate("2015-01-01T00:00:00Z") }
      

      MongoDB 2.6.5:

      replset:PRIMARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) })
      0 : PRIMARY
      1 : SECONDARY
      2 : SECONDARY
      replset:PRIMARY>
      replset:PRIMARY> var date1 = new ISODate("2013-01-01T00:00:00Z");
      replset:PRIMARY> var date2 = new ISODate("2014-01-01T00:00:00Z");
      replset:PRIMARY> var date3 = new ISODate("2015-01-01T00:00:00Z");
      replset:PRIMARY>
      replset:PRIMARY> db.foo.insert({_id: "ABC", when: date1})
      WriteResult({ "nInserted" : 1 })
      replset:PRIMARY> db.foo.update({
      ...    _id: /[A-Z]/,
      ...    when: { $gte: date2 },
      ... },{
      ...    $set:{ when: date3 }
      ... },{
      ...    multi: true, upsert: true
      ... });
      WriteResult({
      	"nMatched" : 0,
      	"nUpserted" : 1,
      	"nModified" : 0,
      	"_id" : ObjectId("547c54560419129296905c7f")
      })
      replset:PRIMARY>
      replset:PRIMARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) })
      0 : PRIMARY
      1 : SECONDARY
      2 : SECONDARY
      replset:PRIMARY>
      replset:PRIMARY> db.foo.find()
      { "_id" : "ABC", "when" : ISODate("2013-01-01T00:00:00Z") }
      { "_id" : ObjectId("547c54560419129296905c7f"), "when" : ISODate("2015-01-01T00:00:00Z") }
      
      Show
      MongoDB 2.4.12: > rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) }) 0 : PRIMARY 1 : SECONDARY 2 : SECONDARY replset:PRIMARY> replset:PRIMARY> var date1 = new ISODate("2013-01-01T00:00:00Z"); replset:PRIMARY> var date2 = new ISODate("2014-01-01T00:00:00Z"); replset:PRIMARY> var date3 = new ISODate("2015-01-01T00:00:00Z"); replset:PRIMARY> replset:PRIMARY> db.foo.insert({_id: "ABC", when: date1}) replset:PRIMARY> db.foo.update({ ... _id: /[A-Z]/, ... when: { $gte: date2 }, ... },{ ... $set:{ when: date3 } ... },{ ... multi: true, upsert: true ... }); replset:PRIMARY> replset:PRIMARY> Mon Dec 1 11:39:28.030 DBClientCursor::init call() failed > Mon Dec 1 11:39:29.166 trying reconnect to 127.0.0.1:27017 Mon Dec 1 11:39:29.167 reconnect 127.0.0.1:27017 ok replset:SECONDARY> replset:SECONDARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) }) 0 : SECONDARY 1 : (not reachable/healthy) 2 : (not reachable/healthy) replset:SECONDARY> replset:SECONDARY> rs.slaveOk() replset:SECONDARY> db.foo.find() { "_id" : "ABC", "when" : ISODate("2013-01-01T00:00:00Z") } { "_id" : /[A-Z]/, "when" : ISODate("2015-01-01T00:00:00Z") } MongoDB 2.6.5: replset:PRIMARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) }) 0 : PRIMARY 1 : SECONDARY 2 : SECONDARY replset:PRIMARY> replset:PRIMARY> var date1 = new ISODate("2013-01-01T00:00:00Z"); replset:PRIMARY> var date2 = new ISODate("2014-01-01T00:00:00Z"); replset:PRIMARY> var date3 = new ISODate("2015-01-01T00:00:00Z"); replset:PRIMARY> replset:PRIMARY> db.foo.insert({_id: "ABC", when: date1}) WriteResult({ "nInserted" : 1 }) replset:PRIMARY> db.foo.update({ ... _id: /[A-Z]/, ... when: { $gte: date2 }, ... },{ ... $set:{ when: date3 } ... },{ ... multi: true, upsert: true ... }); WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("547c54560419129296905c7f") }) replset:PRIMARY> replset:PRIMARY> rs.status().members.forEach(function(doc) { print(doc._id, ":", doc.stateStr) }) 0 : PRIMARY 1 : SECONDARY 2 : SECONDARY replset:PRIMARY> replset:PRIMARY> db.foo.find() { "_id" : "ABC", "when" : ISODate("2013-01-01T00:00:00Z") } { "_id" : ObjectId("547c54560419129296905c7f"), "when" : ISODate("2015-01-01T00:00:00Z") }

      Upserting a document where the the '_id' field in the query pattern is a regex results in a new document being created with the regex being stored in the '_id' field. This can lead to duplicate key errors on the secondaries when they process the oplog, resulting in a crash.

      I have tested this on MongoDB 2.4.6 and 2.4.12 - both versions are affected.

      MongoDB 2.6.5 handles this case differently and inserts the new document with an ObjectId for the '_id' field. As such, it does not appear to be affected.

            Assignee:
            Unassigned Unassigned
            Reporter:
            ronan.bohan@mongodb.com Ronan Bohan
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: