예제 #1
0
파일: oplog.cpp 프로젝트: ALFIO/mongo
        virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            
            if ( cmdObj.firstElement().type() != Array ){
                errmsg = "ops has to be an array";
                return false;
            }
            
            BSONObj ops = cmdObj.firstElement().Obj();
            
            { // check input
                BSONObjIterator i( ops );
                while ( i.more() ){
                    BSONElement e = i.next();
                    if ( e.type() == Object )
                        continue;
                    errmsg = "op not an object: ";
                    errmsg += e.fieldName();
                    return false;
                }
            }
            
            if ( cmdObj["preCondition"].type() == Array ){
                BSONObjIterator i( cmdObj["preCondition"].Obj() );
                while ( i.more() ){
                    BSONObj f = i.next().Obj();
                    
                    BSONObj realres = db.findOne( f["ns"].String() , f["q"].Obj() );
                    
                    Matcher m( f["res"].Obj() );
                    if ( ! m.matches( realres ) ){
                        result.append( "got" , realres );
                        result.append( "whatFailed" , f );
                        errmsg = "pre-condition failed";
                        return false;
                    }
                }
            }
            
            // apply
            int num = 0;
            BSONObjIterator i( ops );
            while ( i.more() ){
                BSONElement e = i.next();
                applyOperation_inlock( e.Obj() , false );
                num++;
            }
            
            result.append( "applied" , num );

            if ( ! fromRepl ){
                // We want this applied atomically on slaves
                // so we re-wrap without the pre-condition for speed
                
                string tempNS = str::stream() << dbname << ".$cmd";
                
                logOp( "c" , tempNS.c_str() , cmdObj.firstElement().wrap() );
            }

            return true;
        }
예제 #2
0
    void ReplSource::applyOperation(const BSONObj& op) {
        try {
            bool failedUpdate = applyOperation_inlock( op );
            if (failedUpdate) {
                Sync sync(hostName);
                if (sync.shouldRetry(op)) {
                    uassert(15914, "Failure retrying initial sync update", !applyOperation_inlock(op));
                }
            }
        }
        catch ( UserException& e ) {
            log() << "sync: caught user assertion " << e << " while applying op: " << op << endl;;
        }
        catch ( DBException& e ) {
            log() << "sync: caught db exception " << e << " while applying op: " << op << endl;;
        }

    }
예제 #3
0
파일: repl.cpp 프로젝트: CoolCloud/mongo
    void ReplSource::applyOperation(const BSONObj& op) {
        try {
            applyOperation_inlock( op );
        }
        catch ( UserException& e ) {
            log() << "sync: caught user assertion " << e << " while applying op: " << op << endl;;
        }
        catch ( DBException& e ) {
            log() << "sync: caught db exception " << e << " while applying op: " << op << endl;;
        }

    }
예제 #4
0
        void run() {
            create();

            BSONObjBuilder b;
            b.appendTimestamp("ts", OpTime::now().asLL());
            b.append("op", "u");
            b.append("o", BSON("$set" << BSON("x" << 456)));
            b.append("o2", BSON("_id" << 123 << "x" << 123));
            b.append("ns", _ns);

            // in an annoying twist of api, returns true on failure
            assert(applyOperation_inlock(b.obj(), true));
        }
예제 #5
0
파일: rs_sync.cpp 프로젝트: mgood/mongo
    void ReplSetImpl::syncApply(const BSONObj &o) {
        //const char *op = o.getStringField("op");
        
        char db[MaxDatabaseLen];
        const char *ns = o.getStringField("ns");
        nsToDatabase(ns, db);

        if ( *ns == '.' || *ns == 0 ) {
            log() << "replSet skipping bad op in oplog: " << o.toString() << endl;
            return;
        }

        Client::Context ctx(ns);
        ctx.getClient()->curop()->reset();

        /* todo : if this asserts, do we want to ignore or not? */
        applyOperation_inlock(o);
    }
예제 #6
0
    /* apply the log op that is in param o
       @return bool success (true) or failure (false)
    */
    bool SyncTail::syncApply(
                        OperationContext* txn, const BSONObj &op, bool convertUpdateToUpsert) {
        const char *ns = op.getStringField("ns");
        verify(ns);

        if ( (*ns == '\0') || (*ns == '.') ) {
            // this is ugly
            // this is often a no-op
            // but can't be 100% sure
            if( *op.getStringField("op") != 'n' ) {
                error() << "replSet skipping bad op in oplog: " << op.toString() << rsLog;
            }
            return true;
        }

        bool isCommand(op["op"].valuestrsafe()[0] == 'c');

        boost::scoped_ptr<Lock::ScopedLock> lk;

        if(isCommand) {
            // a command may need a global write lock. so we will conservatively go 
            // ahead and grab one here. suboptimal. :-(
            lk.reset(new Lock::GlobalWrite(txn->lockState()));
        } else {
            // DB level lock for this operation
            lk.reset(new Lock::DBWrite(txn->lockState(), ns)); 
        }

        Client::Context ctx(ns);
        ctx.getClient()->curop()->reset();
        // For non-initial-sync, we convert updates to upserts
        // to suppress errors when replaying oplog entries.
        bool ok = !applyOperation_inlock(txn, ctx.db(), op, true, convertUpdateToUpsert);
        opsAppliedStats.increment();
        txn->recoveryUnit()->commitIfNeeded();

        return ok;
    }
예제 #7
0
        virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {

            if ( cmdObj.firstElement().type() != Array ) {
                errmsg = "ops has to be an array";
                return false;
            }

            BSONObj ops = cmdObj.firstElement().Obj();

            {
                // check input
                BSONObjIterator i( ops );
                while ( i.more() ) {
                    BSONElement e = i.next();
                    if ( e.type() == Object )
                        continue;
                    errmsg = "op not an object: ";
                    errmsg += e.fieldName();
                    return false;
                }
            }

            if ( cmdObj["preCondition"].type() == Array ) {
                BSONObjIterator i( cmdObj["preCondition"].Obj() );
                while ( i.more() ) {
                    BSONObj f = i.next().Obj();

                    BSONObj realres = db.findOne( f["ns"].String() , f["q"].Obj() );

                    Matcher m( f["res"].Obj() );
                    if ( ! m.matches( realres ) ) {
                        result.append( "got" , realres );
                        result.append( "whatFailed" , f );
                        errmsg = "pre-condition failed";
                        return false;
                    }
                }
            }

            // apply
            int num = 0;
            int errors = 0;
            
            BSONObjIterator i( ops );
            BSONArrayBuilder ab;
            const bool alwaysUpsert = cmdObj.hasField("alwaysUpsert") ?
                    cmdObj["alwaysUpsert"].trueValue() : true;
            
            while ( i.more() ) {
                BSONElement e = i.next();
                const BSONObj& temp = e.Obj();
                
                Client::Context ctx(temp["ns"].String());
                bool failed = applyOperation_inlock(temp, false, alwaysUpsert);
                ab.append(!failed);
                if ( failed )
                    errors++;

                num++;
            }

            result.append( "applied" , num );
            result.append( "results" , ab.arr() );

            if ( ! fromRepl ) {
                // We want this applied atomically on slaves
                // so we re-wrap without the pre-condition for speed

                string tempNS = str::stream() << dbname << ".$cmd";

                // TODO: possibly use mutable BSON to remove preCondition field
                // once it is available
                BSONObjIterator iter(cmdObj);
                BSONObjBuilder cmdBuilder;

                while (iter.more()) {
                    BSONElement elem(iter.next());
                    if (strcmp(elem.fieldName(), "preCondition") != 0) {
                        cmdBuilder.append(elem);
                    }
                }

                logOp("c", tempNS.c_str(), cmdBuilder.done());
            }

            return errors == 0;
        }
예제 #8
0
        virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {

            if ( cmdObj.firstElement().type() != Array ) {
                errmsg = "ops has to be an array";
                return false;
            }

            BSONObj ops = cmdObj.firstElement().Obj();

            {
                // check input
                BSONObjIterator i( ops );
                while ( i.more() ) {
                    BSONElement e = i.next();
                    if ( e.type() == Object )
                        continue;
                    errmsg = "op not an object: ";
                    errmsg += e.fieldName();
                    return false;
                }
            }

            // SERVER-4328 todo : is global ok or does this take a long time? i believe multiple 
            // ns used so locking individually requires more analysis
            Lock::GlobalWrite globalWriteLock;
            DurTransaction txn;

            // Preconditions check reads the database state, so needs to be done locked
            if ( cmdObj["preCondition"].type() == Array ) {
                BSONObjIterator i( cmdObj["preCondition"].Obj() );
                while ( i.more() ) {
                    BSONObj f = i.next().Obj();

                    BSONObj realres = db.findOne( f["ns"].String() , f["q"].Obj() );

                    // Apply-ops would never have a $where matcher, so use the default callback,
                    // which will throw an error if $where is found.
                    Matcher m(f["res"].Obj());
                    if ( ! m.matches( realres ) ) {
                        result.append( "got" , realres );
                        result.append( "whatFailed" , f );
                        errmsg = "pre-condition failed";
                        return false;
                    }
                }
            }

            // apply
            int num = 0;
            int errors = 0;
            
            BSONObjIterator i( ops );
            BSONArrayBuilder ab;
            const bool alwaysUpsert = cmdObj.hasField("alwaysUpsert") ?
                    cmdObj["alwaysUpsert"].trueValue() : true;
            
            while ( i.more() ) {
                BSONElement e = i.next();
                const BSONObj& temp = e.Obj();

                string ns = temp["ns"].String();

                // Run operations under a nested lock as a hack to prevent them from yielding.
                //
                // The list of operations is supposed to be applied atomically; yielding would break
                // atomicity by allowing an interruption or a shutdown to occur after only some
                // operations are applied.  We are already locked globally at this point, so taking
                // a DBWrite on the namespace creates a nested lock, and yields are disallowed for
                // operations that hold a nested lock.
                Lock::DBWrite lk(ns);
                invariant(Lock::nested());

                Client::Context ctx(ns);
                bool failed = applyOperation_inlock(&txn, ctx.db(), temp, false, alwaysUpsert);
                ab.append(!failed);
                if ( failed )
                    errors++;

                num++;

                logOpForDbHash(ns.c_str());
            }

            result.append( "applied" , num );
            result.append( "results" , ab.arr() );

            if ( ! fromRepl ) {
                // We want this applied atomically on slaves
                // so we re-wrap without the pre-condition for speed

                string tempNS = str::stream() << dbname << ".$cmd";

                // TODO: possibly use mutable BSON to remove preCondition field
                // once it is available
                BSONObjIterator iter(cmdObj);
                BSONObjBuilder cmdBuilder;

                while (iter.more()) {
                    BSONElement elem(iter.next());
                    if (strcmp(elem.fieldName(), "preCondition") != 0) {
                        cmdBuilder.append(elem);
                    }
                }

                logOp(&txn, "c", tempNS.c_str(), cmdBuilder.done());
            }

            return errors == 0;
        }
예제 #9
0
 // returns true on success, false on failure
 bool apply(const BSONObj& op) {
     Client::Context ctx( _cappedNs );
     OperationContextImpl txn;
     // in an annoying twist of api, returns true on failure
     return !applyOperation_inlock(&txn, ctx.db(), op, true);
 }
예제 #10
0
 // returns true on success, false on failure
 bool apply(const BSONObj& op) {
     Client::Context ctx( _ns );
     // in an annoying twist of api, returns true on failure
     return !applyOperation_inlock(op, true);
 }