void rollbackTransactionFromOplog(BSONObj entry, bool purgeEntry) { bool transactionAlreadyApplied = entry["a"].Bool(); Client::Transaction transaction(DB_SERIALIZABLE); if (transactionAlreadyApplied) { if (entry.hasElement("ref")) { rollbackRefOp(entry); } else if (entry.hasElement("ops")) { rollbackOps(entry["ops"].Array()); } else { verify(0); } } { LOCK_REASON(lockReason, "repl: purging entry from oplog"); Lock::DBRead lk1("local", lockReason); if (purgeEntry) { purgeEntryFromOplog(entry); } else { // set the applied bool to false, to let the oplog know that // this entry has not been applied to collections BSONElementManipulator(entry["a"]).setBool(false); writeEntryToOplog(entry, false); } } transaction.commit(DB_TXN_NOSYNC); }
// takes an entry that was written _logTransactionOps // and applies them to collections // // TODO: possibly improve performance of this. We create and destroy a // context for each operation. Find a way to amortize it out if necessary // void applyTransactionFromOplog(BSONObj entry) { bool transactionAlreadyApplied = entry["a"].Bool(); if (!transactionAlreadyApplied) { Client::Transaction transaction(DB_SERIALIZABLE); if (entry.hasElement("ref")) { applyRefOp(entry); } else if (entry.hasElement("ops")) { applyOps(entry["ops"].Array()); } else { verify(0); } // set the applied bool to true, to let the oplog know that // this entry has been applied to collections BSONElementManipulator(entry["a"]).setBool(true); { LOCK_REASON(lockReason, "repl: setting oplog entry's applied bit"); Lock::DBRead lk1("local", lockReason); writeEntryToOplog(entry, false); } // If this code fails, it is impossible to recover from // because we don't know if the transaction successfully committed // so we might as well crash // There is currently no known way this code can throw an exception try { // we are operating as a secondary. We don't have to fsync transaction.commit(DB_TXN_NOSYNC); } catch (std::exception &e) { log() << "exception during commit of applyTransactionFromOplog, aborting system: " << e.what() << endl; printStackTrace(); logflush(); ::abort(); } } }
void logTransactionOpsRef(GTID gtid, uint64_t timestamp, uint64_t hash, OID& oid) { Lock::DBRead lk1("local"); BSONObjBuilder b; addGTIDToBSON("_id", gtid, b); b.appendDate("ts", timestamp); b.append("h", (long long)hash); b.append("a", true); b.append("ref", oid); BSONObj bb = b.done(); writeEntryToOplog(bb, true); }
static void _logTransactionOps(GTID gtid, uint64_t timestamp, uint64_t hash, BSONArray& opInfo) { Lock::DBRead lk1("local"); BSONObjBuilder b; addGTIDToBSON("_id", gtid, b); b.appendDate("ts", timestamp); b.append("h", (long long)hash); b.append("a", true); b.append("ops", opInfo); BSONObj bb = b.done(); // write it to oplog LOG(3) << "writing " << bb.toString(false, true) << " to master " << endl; writeEntryToOplog(bb, true); }
// assumes oplog is read locked on entry void replicateTransactionToOplog(BSONObj& op) { // set the applied bool to false, to let the oplog know that // this entry has not been applied to collections BSONElementManipulator(op["a"]).setBool(false); writeEntryToOplog(op, true); }