예제 #1
0
    void logDelete(const char* ns, BSONObj row, bool fromMigrate, TxnContext* txn) {
        bool logForSharding = !fromMigrate && shouldLogTxnOpForSharding(OP_STR_DELETE, ns, row);
        if (logTxnOpsForReplication() || logForSharding) {
            BSONObjBuilder b;
            if (isLocalNs(ns)) {
                return;
            }

            appendOpType(OP_STR_DELETE, &b);
            appendNsStr(ns, &b);
            appendMigrate(fromMigrate, &b);
            b.append(KEY_STR_ROW, row);
            BSONObj logObj = b.obj();
            if (logTxnOpsForReplication()) {
                txn->logOpForReplication(logObj);
            }
            if (logForSharding) {
                txn->logOpForSharding(logObj);
            }
        }
    }
예제 #2
0
 void TxnOplog::writeOpsDirectlyToOplog(GTID gtid, uint64_t timestamp, uint64_t hash) {
     dassert(logTxnOpsForReplication());
     dassert(_logTxnToOplog);
     // build array of in memory ops
     BSONArrayBuilder b;
     for (deque<BSONObj>::iterator it = _m.begin(); it != _m.end(); it++) {
         b.append(*it);
     }
     BSONArray a = b.arr();
     // log ops
     _logTxnToOplog(gtid, timestamp, hash, a);
 }
예제 #3
0
    void logCommand(const char* ns, BSONObj row, TxnContext* txn) {
        // We do not need to log for sharding because commands are only logged right now if they
        // take a write lock, and we have a read lock the whole time we're logging things for
        // sharding.  TODO: If this changes, we need to start logging commands.
        if (logTxnOpsForReplication()) {
            BSONObjBuilder b;
            if (isLocalNs(ns)) {
                return;
            }

            appendOpType(OP_STR_COMMAND, &b);
            appendNsStr(ns, &b);
            b.append(KEY_STR_ROW, row);
            txn->logOpForReplication(b.obj());
        }
    }
예제 #4
0
    void logInsertForCapped(
        const char* ns, 
        BSONObj pk, 
        BSONObj row, 
        TxnContext* txn
        ) 
    {
        if (logTxnOpsForReplication()) {
            BSONObjBuilder b;
            if (isLocalNs(ns)) {
                return;
            }

            appendOpType(OP_STR_CAPPED_INSERT, &b);
            appendNsStr(ns, &b);
            b.append(KEY_STR_PK, pk);
            b.append(KEY_STR_ROW, row);
            txn->logOpForReplication(b.obj());
        }
    }
예제 #5
0
 void TxnContext::logOpForReplication(BSONObj op) {
     dassert(logTxnOpsForReplication());
     _txnOps.appendOp(op);
 }
예제 #6
0
    void TxnContext::commit(int flags) {
        verify(!_retired);
        bool gotGTID = false;
        GTID gtid;
        // do this in case we are writing the first entry
        // we put something in that can be distinguished from
        // an initialized GTID that has never been touched
        gtid.inc_primary(); 
        // handle work related to logging of transaction for replication
        // this piece must be done before the _txn.commit
        try {
            if (hasParent()) {
                // This does something
                // a bit dangerous in that it may spill parent's stuff
                // with this child transaction that is committing. If something
                // goes wrong and this child transaction aborts, we will miss
                // some ops
                //
                // This ought to be ok, because we are in this try/catch block
                // where if something goes wrong, we will crash the server.
                // NOTHING better go wrong here, unless under bad rare
                // circumstances
                _txnOps.finishChildCommit();
            }
            else if (!_txnOps.empty()) {
                uint64_t timestamp = 0;
                uint64_t hash = 0;
                if (!_initiatingRS) {
                    dassert(txnGTIDManager);
                    txnGTIDManager->getGTIDForPrimary(&gtid, &timestamp, &hash);
                }
                else {
                    dassert(!txnGTIDManager);
                    timestamp = curTimeMillis64();
                }
                gotGTID = true;
                // In this case, the transaction we are committing has
                // no parent, so we must write the transaction's 
                // logged operations to the opLog, as part of this transaction
                dassert(logTxnOpsForReplication());
                dassert(_logTxnToOplog);
                _txnOps.rootCommit(gtid, timestamp, hash);
            }
            // handle work related to logging of transaction for chunk migrations
            if (!_txnOpsForSharding.empty()) {
                if (hasParent()) {
                    transferOpsForShardingToParent();
                }
                else {
                    writeTxnOpsToMigrateLog();
                }
            }

            _clientCursorRollback.preComplete();
            _txn.commit(flags);

            // if the commit of this transaction got a GTID, then notify 
            // the GTIDManager that the commit is now done.
            if (gotGTID && !_initiatingRS) {
                dassert(txnGTIDManager);
                // save the GTID for the client so that
                // getLastError will know what GTID slaves
                // need to be caught up to.
                cc().setLastOp(gtid);
                txnGTIDManager->noteLiveGTIDDone(gtid);
            }
        }
        catch (std::exception &e) {
            log() << "exception during critical section of txn commit, aborting system: " << e.what() << endl;
            printStackTrace();
            logflush();
            ::abort();
        }

        // These rollback items must be processed after the ydb transaction completes.
        if (hasParent()) {
            _cappedRollback.transfer(_parent->_cappedRollback);
            _nsIndexRollback.transfer(_parent->_nsIndexRollback);
        } else {
            _cappedRollback.commit();
            _nsIndexRollback.commit();
        }
        _retired = true;
    }