Is there a way to clear/wipe the oplog for an existing replicated cluster?

5,802 views
Skip to first unread message

Nathan Neulinger

unread,
May 16, 2017, 12:22:29 AM5/16/17
to mongodb-user
I have an existing replicated cluster (2+1A). Due to some data privacy/compliance issues, it was necessary to remove a document from the database. It has subsequently come to my attention that we need to pull this content completely from the system - and I interpret that as including oplog content. 

I realize I could take a complete outage and reset the oplog/recreate the replication pair - but is there a better way? I read something about 'emptycapped' but no specific details about how this should be used in relation to the oplog (or even if it can be).

Alternatively, is it possible to alter content within the oplog - i.e. to issue an update to mask over a given value if found?



My fallback position is a shutdown and reset followed by a clean restore of a db snapshot following the removal from the live collections. This will cause a much more significant outage though. 

-- Nathan

Rhys Campbell

unread,
May 16, 2017, 8:12:56 AM5/16/17
to mongodb-user
Looks like it's possible but restricted...

shard0:PRIMARY> db.oplog.rs.deleteOne({});
2017-05-16T14:05:21.017+0200 E QUERY    [thread1] uncaught exception: WriteError({
       
"index" : 0,
       
"code" : 20,
       
"errmsg" : "cannot remove from a capped collection: local.oplog.rs",
       
"op" : {
               
"q" : {


               
},
               
"limit" : 1
       
}
}) :
undefined
shard0
:PRIMARY> db.oplog.rs.update({ "ts" : Timestamp(1439476574, 1), "o.msg": "initiating set" }, { "$set": { "o.msg": "Redacted" } });
WriteResult({
       
"nMatched" : 0,
       
"nUpserted" : 0,
       
"nModified" : 0,
       
"writeError" : {
               
"code" : 10003,
               
"errmsg" : "Cannot change the size of a document in a capped collection: 86 != 80"
       
}
})
shard0
:PRIMARY> db.oplog.rs.update({ "ts" : Timestamp(1439476574, 1), "o.msg": "initiating set" }, { "$set": { "o.msg": "Redacted      " } });
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
shard0
:PRIMARY> db.oplog.rs.findOne()
{
       
"ts" : Timestamp(1439476574, 1),
       
"h" : NumberLong(0),
       
"v" : 2,
       
"op" : "n",
       
"ns" : "",
       
"o" : {
               
"msg" : "Redacted      "
       
}
}

Deletes not possible but you can update them. Update have to result in a document of equal size to the original (I just padded mine with spaces above). Also it seems these are not execute on the SECONDARY nodes so you'd need to do it there too. I've no idea how safe this is or not so use at your own risk.

Cheers,

Rhys

John Reno

unread,
May 16, 2017, 10:57:31 AM5/16/17
to mongodb-user

Hi, the simplest way to clear the oplog is to resize it. See https://docs.mongodb.com/manual/tutorial/change-oplog-size/. Here is a snippet of code which may help:

 print("Starting oplog resize, before:");
 rs.printReplicationInfo();
 //
 //     Save the last oplog record and resize the log
 //
 db = db.getSiblingDB('local');
 db.tempOplogRec.drop();
 db.tempOplogRec.save( db.oplog.rs.find( { }, { ts: 1, h: 1 } ).sort( {$natural : -1} ).limit(1).next() )
 if (db.oplog.rs.count() == 0)
    { throw new Error("Save of last oplog record failed, aborting");
 };
 db.oplog.rs.drop()
 db.runCommand( { create: "oplog.rs", capped: true, size: (newSize * 1024 * 1024 * 1024) } )
 db.oplog.rs.save( db.tempOplogRec.findOne() )
 print("Oplog resized to " + newSize + "GB");
 print("Done with oplog resize, after:");
 rs.printReplicationInfo();
}

I strongly suggest you practice on a throwaway replica set first! You will need to perform a rolling shutdown of the replica set.

Thanks, jlr

Reply all
Reply to author
Forward
0 new messages