Beispiel #1
0
 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);
 }
Beispiel #2
0
        bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
            bool all = *cmdObj.firstElement().valuestrsafe() == '*';

            int before = result.len();

            // TODO: convert to ServerParameters -- SERVER-10515

            if (isJournalingEnabled() && (all || cmdObj.hasElement("journalCommitInterval")) &&
                !isMongos()) {
                result.append("journalCommitInterval",
                              getJournalCommitInterval());
            }
            if( all || cmdObj.hasElement( "traceExceptions" ) ) {
                result.append("traceExceptions",
                              DBException::traceExceptions);
            }
            if( all || cmdObj.hasElement( "replMonitorMaxFailedChecks" ) ) {
                result.append("replMonitorMaxFailedChecks",
                              ReplicaSetMonitor::getMaxFailedChecks());
            }

            const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap();
            for ( ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i ) {
                if ( all || cmdObj.hasElement( i->first.c_str() ) ) {
                    i->second->append( result, i->second->name() );
                }
            }

            if ( before == result.len() ) {
                errmsg = "no option found to get";
                return false;
            }
            return true;
        }
Beispiel #3
0
        virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            log() << "replSet replSetTest command received: " << cmdObj.toString() << rsLog;

            if (!checkAuth(errmsg, result)) {
                return false;
            }

            if( cmdObj.hasElement("forceInitialSyncFailure") ) {
                replSetForceInitialSyncFailure = (unsigned) cmdObj["forceInitialSyncFailure"].Number();
                return true;
            }

            if( !check(errmsg, result) )
                return false;

            if( cmdObj.hasElement("blind") ) {
                replSetBlind = cmdObj.getBoolField("blind");
                return true;
            }

            if (cmdObj.hasElement("sethbmsg")) {
                replset::sethbmsg(cmdObj["sethbmsg"].String());
                return true;
            }

            return false;
        }
Beispiel #4
0
 // 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();
         }
     }
 }
Beispiel #5
0
        bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
            bool all = *cmdObj.firstElement().valuestrsafe() == '*';
            
            int before = result.len();
            
            if( all || cmdObj.hasElement("quiet") ) {
                result.append("quiet", cmdLine.quiet );
            }
            if( all || cmdObj.hasElement("notablescan") ) {
                result.append("notablescan", cmdLine.noTableScan);
            }
            if( all || cmdObj.hasElement("logLevel") ) {
                result.append("logLevel", logLevel);
            }
            if( all || cmdObj.hasElement("syncdelay") ) {
                result.append("syncdelay", cmdLine.syncdelay);
            }
            if( all || cmdObj.hasElement("replApplyBatchSize") ) {
                result.append("replApplyBatchSize", replApplyBatchSize);
            }           

            if ( before == result.len() ) {
                errmsg = "no option found to get";
                return false;
            }
            return true;
        }
Beispiel #6
0
        Config::OutputOptions Config::parseOutputOptions(const std::string& dbname,
                                                         const BSONObj& cmdObj) {
            Config::OutputOptions outputOptions;

            outputOptions.outNonAtomic = false;
            if (cmdObj["out"].type() == String) {
                outputOptions.collectionName = cmdObj["out"].String();
                outputOptions.outType = REPLACE;
            }
            else if (cmdObj["out"].type() == Object) {
                BSONObj o = cmdObj["out"].embeddedObject();

                BSONElement e = o.firstElement();
                string t = e.fieldName();

                if (t == "normal" || t == "replace") {
                    outputOptions.outType = REPLACE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "merge") {
                    outputOptions.outType = MERGE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "reduce") {
                    outputOptions.outType = REDUCE;
                    outputOptions.collectionName = e.String();
                }
                else if (t == "inline") {
                    outputOptions.outType = INMEMORY;
                }
                else {
                    uasserted(13522,
                              mongoutils::str::stream() << "unknown out specifier [" << t << "]");
                }

                if (o.hasElement("db")) {
                    outputOptions.outDB = o["db"].String();
                }

                if (o.hasElement("nonAtomic")) {
                    outputOptions.outNonAtomic = o["nonAtomic"].Bool();
                    if (outputOptions.outNonAtomic)
                        uassert(15895,
                                "nonAtomic option cannot be used with this output type",
                                (outputOptions.outType == REDUCE ||
                                         outputOptions.outType == MERGE));
                }
            }
            else {
                uasserted(13606 , "'out' has to be a string or an object");
            }

            if (outputOptions.outType != INMEMORY) {
                outputOptions.finalNamespace = mongoutils::str::stream()
                    << (outputOptions.outDB.empty() ? dbname : outputOptions.outDB)
                    << "." << outputOptions.collectionName;
            }

            return outputOptions;
        }
Beispiel #7
0
        virtual bool run(const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            string coll = cmdObj.firstElement().valuestr();
            if( coll.empty() || db.empty() ) {
                errmsg = "no collection name specified";
                return false;
            }

            if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { 
                errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force";
                return false;
            }
            
            string ns = db + '.' + coll;
            if ( ! NamespaceString::normal(ns.c_str()) ) {
                errmsg = "bad namespace name";
                return false;
            }
            
            // parameter validation to avoid triggering assertions in compact()
            if ( str::contains(ns, ".system.") ) {
                errmsg = "can't compact a system namespace";
                return false;
            }
            
            {
                writelock lk;
                Client::Context ctx(ns);
                NamespaceDetails *d = nsdetails(ns.c_str());
                if( ! d ) {
                    errmsg = "namespace does not exist";
                    return false;
                }

                if ( d->capped ) {
                    errmsg = "cannot compact a capped collection";
                    return false;
                }
            }

            double pf = 1.0;
            int pb = 0;
            if( cmdObj.hasElement("paddingFactor") ) {
                pf = cmdObj["paddingFactor"].Number();
                assert( pf >= 1.0 && pf <= 4.0 );
            }
            if( cmdObj.hasElement("paddingBytes") ) {
                pb = (int) cmdObj["paddingBytes"].Number();
                assert( pb >= 0 && pb <= 1024 * 1024 );
            }

            bool validate = !cmdObj.hasElement("validate") || cmdObj["validate"].trueValue(); // default is true at the moment
            bool ok = compact(ns, errmsg, validate, result, pf, pb);
            return ok;
        }
Beispiel #8
0
        void up(const BSONObj& info, HeartbeatInfo& mem) {
            HeartbeatInfo::numPings++;
            mem.authIssue = false;

            if( mem.upSince == 0 ) {
                log() << "replSet member " << h.toString() << " is up" << rsLog;
                mem.upSince = mem.lastHeartbeat;
            }
            mem.health = 1.0;
            mem.lastHeartbeatMsg = info["hbmsg"].String();
            if (info.hasElement("syncingTo")) {
                mem.syncingTo = info["syncingTo"].String();
            }

            if( info.hasElement("opTime") )
                mem.opTime = info["opTime"].Date();

            // see if this member is in the electable set
            if( info["e"].eoo() ) {
                // for backwards compatibility
                const Member *member = theReplSet->findById(mem.id());
                if (member && member->config().potentiallyHot()) {
                    theReplSet->addToElectable(mem.id());
                }
                else {
                    theReplSet->rmFromElectable(mem.id());
                }
            }
            // add this server to the electable set if it is within 10
            // seconds of the latest optime we know of
            else if( info["e"].trueValue() &&
                     mem.opTime >= theReplSet->lastOpTimeWritten.getSecs() - 10) {
                unsigned lastOp = theReplSet->lastOtherOpTime().getSecs();
                if (lastOp > 0 && mem.opTime >= lastOp - 10) {
                    theReplSet->addToElectable(mem.id());
                }
            }
            else {
                theReplSet->rmFromElectable(mem.id());
            }

            be cfg = info["config"];
            if( cfg.ok() ) {
                // received a new config
                boost::function<void()> f =
                    boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
                theReplSet->mgr->send(f);
            }
        }
Beispiel #9
0
bool Query::isComplex(const BSONObj& obj, bool* hasDollar) {
    if (obj.hasElement("query")) {
        if (hasDollar)
            *hasDollar = false;
        return true;
    }

    if (obj.hasElement("$query")) {
        if (hasDollar)
            *hasDollar = true;
        return true;
    }

    return false;
}
Beispiel #10
0
    virtual bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
        log() << "replSet replSetTest command received: " << cmdObj.toString() << rsLog;
        if( cmdObj.hasElement("forceInitialSyncFailure") ) {
            replSetForceInitialSyncFailure = (unsigned) cmdObj["forceInitialSyncFailure"].Number();
            return true;
        }

        // may not need this, but if removed check all tests still work:
        if( !check(errmsg, result) )
            return false;

        if( cmdObj.hasElement("blind") ) {
            replSetBlind = cmdObj.getBoolField("blind");
            return true;
        }
        return false;
    }
Beispiel #11
0
    virtual bool errmsgRun(OperationContext* opCtx,
                           const string& db,
                           const BSONObj& cmdObj,
                           string& errmsg,
                           BSONObjBuilder& result) {
        NamespaceString nss = CommandHelpers::parseNsCollectionRequired(db, cmdObj);

        repl::ReplicationCoordinator* replCoord = repl::ReplicationCoordinator::get(opCtx);
        if (replCoord->getMemberState().primary() && !cmdObj["force"].trueValue()) {
            errmsg =
                "will not run compact on an active replica set primary as this is a slow blocking "
                "operation. use force:true to force";
            return false;
        }

        if (!nss.isNormal()) {
            errmsg = "bad namespace name";
            return false;
        }

        if (nss.isSystem()) {
            // Items in system.* cannot be moved as there might be pointers to them.
            errmsg = "can't compact a system namespace";
            return false;
        }

        CompactOptions compactOptions;

        if (cmdObj.hasElement("validate"))
            compactOptions.validateDocuments = cmdObj["validate"].trueValue();

        AutoGetDb autoDb(opCtx, db, MODE_X);
        Database* const collDB = autoDb.getDb();

        Collection* collection = collDB ? collDB->getCollection(opCtx, nss) : nullptr;
        auto view =
            collDB && !collection ? ViewCatalog::get(collDB)->lookup(opCtx, nss.ns()) : nullptr;

        // If db/collection does not exist, short circuit and return.
        if (!collDB || !collection) {
            if (view)
                uasserted(ErrorCodes::CommandNotSupportedOnView, "can't compact a view");
            else
                uasserted(ErrorCodes::NamespaceNotFound, "collection does not exist");
        }

        OldClientContext ctx(opCtx, nss.ns());
        BackgroundOperation::assertNoBgOpInProgForNs(nss.ns());

        log() << "compact " << nss.ns() << " begin, options: " << compactOptions;

        StatusWith<CompactStats> status = compactCollection(opCtx, collection, &compactOptions);
        uassertStatusOK(status.getStatus());

        log() << "compact " << nss.ns() << " end";

        return true;
    }
Beispiel #12
0
    void replicateFullTransactionToOplog(BSONObj& o, OplogReader& r, bool* bigTxn) {
        *bigTxn = false;
        if (o.hasElement("ref")) {
            OID oid = o["ref"].OID();
            LOG(3) << "oplog ref " << oid << endl;
            copyOplogRefsRange(r, oid);
            *bigTxn = true;
        }

        Client::ReadContext ctx(rsoplog);
        replicateTransactionToOplog(o);
    }
Beispiel #13
0
        bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
            int s = 0;
            if( cmdObj.hasElement("notablescan") ) {
                result.append("was", cmdLine.noTableScan);
                cmdLine.noTableScan = cmdObj["notablescan"].Bool();
                s++;
            }
            if( cmdObj.hasElement("quiet") ) {
                result.append("was", cmdLine.quiet );
                cmdLine.quiet = cmdObj["quiet"].Bool();
                s++;
            }
            if( cmdObj.hasElement("syncdelay") ) {
                result.append("was", cmdLine.syncdelay );
                cmdLine.syncdelay = cmdObj["syncdelay"].Number();
                s++;
            }
            if( cmdObj.hasElement( "logLevel" ) ) {
                result.append("was", logLevel );
                logLevel = cmdObj["logLevel"].numberInt();
                s++;
            }
            if( cmdObj.hasElement( "replApplyBatchSize" ) ) {
                result.append("was", replApplyBatchSize );
                BSONElement e = cmdObj["replApplyBatchSize"];
                ParameterValidator * v = ParameterValidator::get( e.fieldName() );
                assert( v );
                if ( ! v->isValid( e , errmsg ) )
                    return false;
                replApplyBatchSize = e.numberInt();
                s++;
            }

            if( s == 0 ) {
                errmsg = "no option found to set, use '*' to get all ";
                return false;
            }

            return true;
        }
        bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
            int s = 0;
            bool found = setParmsMongodSpecific(dbname, cmdObj, errmsg, result, fromRepl);
            if( cmdObj.hasElement("journalCommitInterval") ) { 
                if( !cmdLine.dur ) { 
                    errmsg = "journaling is off";
                    return false;
                }
                int x = (int) cmdObj["journalCommitInterval"].Number();
                assert( x > 1 && x < 500 );
                cmdLine.journalCommitInterval = x;
                log() << "setParameter journalCommitInterval=" << x << endl;
                s++;
            }
            if( cmdObj.hasElement("notablescan") ) {
                assert( !cmdLine.isMongos() );
                if( s == 0 )
                    result.append("was", cmdLine.noTableScan);
                cmdLine.noTableScan = cmdObj["notablescan"].Bool();
                s++;
            }
            if( cmdObj.hasElement("quiet") ) {
                if( s == 0 )
                    result.append("was", cmdLine.quiet );
                cmdLine.quiet = cmdObj["quiet"].Bool();
                s++;
            }
            if( cmdObj.hasElement("syncdelay") ) {
                assert( !cmdLine.isMongos() );
                if( s == 0 )
                    result.append("was", cmdLine.syncdelay );
                cmdLine.syncdelay = cmdObj["syncdelay"].Number();
                s++;
            }
            if( cmdObj.hasElement( "logLevel" ) ) {
                if( s == 0 )
                    result.append("was", logLevel );
                logLevel = cmdObj["logLevel"].numberInt();
                s++;
            }
            if( cmdObj.hasElement( "replApplyBatchSize" ) ) {
                if( s == 0 )
                    result.append("was", replApplyBatchSize );
                BSONElement e = cmdObj["replApplyBatchSize"];
                ParameterValidator * v = ParameterValidator::get( e.fieldName() );
                assert( v );
                if ( ! v->isValid( e , errmsg ) )
                    return false;
                replApplyBatchSize = e.numberInt();
                s++;
            }

            if( s == 0 && !found ) {
                errmsg = "no option found to set, use help:true to see options ";
                return false;
            }

            return true;
        }
Beispiel #15
0
    void replicateFullTransactionToOplog(BSONObj& o, OplogReader& r, bool* bigTxn) {
        *bigTxn = false;
        if (o.hasElement("ref")) {
            OID oid = o["ref"].OID();
            LOG(3) << "oplog ref " << oid << endl;
            copyOplogRefsRange(r, oid);
            *bigTxn = true;
        }

        LOCK_REASON(lockReason, "repl: copying entry to local oplog");
        Client::ReadContext ctx(rsoplog, lockReason);
        replicateTransactionToOplog(o);
    }
Beispiel #16
0
/**********************************************************
 *reads from db and converts bson to FileRec object
 * 
***********************************************************/
void FileRec::readFromDB(mongo::DBClientConnection& conn, string filename) {

    boost::filesystem::path p(filename); //get filename from path
    string file(p.filename().c_str());
    auto_ptr<mongo::DBClientCursor> cursor = conn.query("fileRecords.Filerec", MONGO_QUERY("filename" << file));

    if (cursor->more()) {

        BSONObj record = cursor->next();
        //get data from db and store in the FileRec
        this->filename = record.getStringField("filename");
        this->tempname = record.getStringField("Tempname");
        this->recentHash = record.getStringField("curhash");
        this->origHash = record.getStringField("ovhash");
        this->length = record.getIntField("length");
        this->versionCount = record.getIntField("nversions");
        this->modifytime.tv_nsec = record.getField("Mtnsec").numberLong();
        this->modifytime.tv_sec = record.getField("mtsec").numberLong();
        this->refNum = record.getIntField("currentversion");

        vector<BSONElement> hashes(record.getField("FileBlkHashes").Array());
        for (vector<BSONElement>::iterator it = hashes.begin(); it != hashes.end(); ++it) {
            appendBlock((*it).String());
        }

        //comments is an array of objects so it takes a bit of nesting to convert
        vector<BSONElement> array = record["comments"].Array(); //convert to array
        for (vector<BSONElement>::iterator ar = array.begin(); ar != array.end(); ++ar) {
            BSONObj commentdata = ar->Obj(); //store object at array[x] into BSONObj
            BSONElement version = commentdata.getField("version"); //convert
            BSONElement commentdb = commentdata.getField("comment");

            comment data;
            data.comment = commentdb.String();
            data.version = version.Int();
            appendComment(data);
        }


        if (record.hasElement("versionrec")) { //again an array of objects
            vector<BSONElement> array = record["versionrec"].Array();
            for (vector<BSONElement>::iterator it = array.begin(); it != array.end(); ++it) {

                BSONObj versionRecord = it->Obj();
                BSONElement id = versionRecord.getField("id");
                appendVersion(id.String());
            }
        } 
    }
}
Beispiel #17
0
        virtual bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            log() << "replSet replSetTest command received: " << cmdObj.toString() << rsLog;

            if( cmdObj.hasElement("forceInitialSyncFailure") ) {
                replSetForceInitialSyncFailure = (unsigned) cmdObj["forceInitialSyncFailure"].Number();
                return true;
            }

            Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result);
            if (!status.isOK())
                return appendCommandStatus(result, status);

            return false;
        }
Beispiel #18
0
 virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
     if( cmdObj.hasElement("expireOplogDays") || cmdObj.hasElement("expireOplogHours") ) {
         uint32_t expireOplogDays = cmdLine.expireOplogDays;
         uint32_t expireOplogHours = cmdLine.expireOplogHours;
         if (cmdObj.hasElement("expireOplogHours")) {
             BSONElement e = cmdObj["expireOplogHours"];
             if (!e.isNumber()) {
                 errmsg = "bad expireOplogHours";
                 return false;
             }
             expireOplogHours = e.numberLong();
         }
         if (cmdObj.hasElement("expireOplogDays")) {
             BSONElement e = cmdObj["expireOplogDays"];
             if (!e.isNumber()) {
                 errmsg = "bad expireOplogDays";
                 return false;
             }
             expireOplogDays = e.numberLong();
         }
         theReplSet->changeExpireOplog(expireOplogDays, expireOplogHours);
     }
     return true;
 }
 bool run(const string& dbname, BSONObj& obj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
     if( !obj.hasElement("servers") ) { 
         vector<string> ips;
         obj["servers"].Obj().Vals(ips);
         {
             SimpleMutex::scoped_lock lk(cloud::mtx);
             cloud::ips.ref(lk).swap(ips);
             if( !cloud::startedThread ) {
                 cloud::startedThread = true;
                 boost::thread thr(cloud::thread);
             }
         }
     }
     return true;
 }
Beispiel #20
0
        virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
            string coll = cmdObj.firstElement().valuestr();
            if( coll.empty() || db.empty() ) {
                errmsg = "no collection name specified";
                return false;
            }

            if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { 
                errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force";
                return false;
            }

            string ns = db + '.' + coll;
            bool validate = !cmdObj.hasElement("validate") || cmdObj["validate"].trueValue(); // default is true at the moment
            bool ok = compact(ns, errmsg, validate, result);
            return ok;
        }
Beispiel #21
0
    void purgeEntryFromOplog(BSONObj entry) {
        verify(rsOplogDetails);
        if (entry.hasElement("ref")) {
            OID oid = entry["ref"].OID();
            Helpers::removeRange(
                rsOplogRefs,
                BSON("_id" << BSON("oid" << oid << "seq" << 0)),
                BSON("_id" << BSON("oid" << oid << "seq" << LLONG_MAX)),
                BSON("_id" << 1),
                true,
                false
                );
        }

        BSONObj pk = entry["_id"].wrap("");
        uint64_t flags = (NamespaceDetails::NO_LOCKTREE);
        rsOplogDetails->deleteObject(pk, entry, flags);
    }
Beispiel #22
0
        bool _requestHeartbeat(HeartbeatInfo& mem, BSONObj& info, int& theirConfigVersion) {
            if (tries++ % threshold == (threshold - 1)) {
                ScopedConn conn(h.toString());
                conn.reconnect();
            }

            Timer timer;
            time_t before = curTimeMicros64() / 1000000;

            bool ok = requestHeartbeat(theReplSet->name(), theReplSet->selfFullName(),
                                       h.toString(), info, theReplSet->config().version, theirConfigVersion);

            mem.ping = (unsigned int)timer.millis();

            // we set this on any response - we don't get this far if
            // couldn't connect because exception is thrown
            time_t after = mem.lastHeartbeat = before + (mem.ping / 1000);

            if ( info["time"].isNumber() ) {
                long long t = info["time"].numberLong();
                if( t > after )
                    mem.skew = (int) (t - after);
                else if( t < before )
                    mem.skew = (int) (t - before); // negative
            }
            else {
                // it won't be there if remote hasn't initialized yet
                if( info.hasElement("time") )
                    warning() << "heatbeat.time isn't a number: " << info << endl;
                mem.skew = INT_MIN;
            }

            {
                be state = info["state"];
                if( state.ok() )
                    mem.hbstate = MemberState(state.Int());
            }

            return ok;
        }
    void SyncClusterConnection::_checkLast() {
        _lastErrors.clear();
        vector<string> errors;

        for ( size_t i=0; i<_conns.size(); i++ ) {
            BSONObj res;
            string err;
            try {
                if ( ! _conns[i]->runCommand( "admin" , BSON( "getlasterror" << 1 << "fsync" << 1 ) , res ) )
                    err = "cmd failed: ";
            }
            catch ( std::exception& e ) {
                err += e.what();
            }
            catch ( ... ) {
                err += "unknown failure";
            }
            _lastErrors.push_back( res.getOwned() );
            errors.push_back( err );
        }

        verify( _lastErrors.size() == errors.size() && _lastErrors.size() == _conns.size() );

        stringstream err;
        bool ok = true;

        for ( size_t i = 0; i<_conns.size(); i++ ) {
            BSONObj res = _lastErrors[i];
            if ( res["ok"].trueValue() && (res["fsyncFiles"].numberInt() > 0 ||
                                           res.hasElement("waited") ||
                                           res["syncMillis"].numberInt() >= 0 ) )
                continue;
            ok = false;
            err << _conns[i]->toString() << ": " << res << " " << errors[i];
        }

        if ( ok )
            return;
        throw UserException( 8001 , (string)"SyncClusterConnection write op failed: " + err.str() );
    }
Beispiel #24
0
    void purgeEntryFromOplog(BSONObj entry) {
        verify(rsOplogDetails);
        if (entry.hasElement("ref")) {
            OID oid = entry["ref"].OID();
            LOCK_REASON(lockReason, "repl: purging oplog.refs for oplog entry");
            Client::ReadContext ctx(rsOplogRefs, lockReason);
            Client::Transaction txn(DB_SERIALIZABLE);
            deleteIndexRange(
                rsOplogRefs,
                BSON("_id" << BSON("oid" << oid << "seq" << 0)),
                BSON("_id" << BSON("oid" << oid << "seq" << LLONG_MAX)),
                BSON("_id" << 1),
                true,
                false
                );
            txn.commit();
        }

        BSONObj pk = entry["_id"].wrap("");
        const uint64_t flags = Collection::NO_LOCKTREE;
        rsOplogDetails->deleteObject(pk, entry, flags);
    }
Beispiel #25
0
    bool run(OperationContext* txn,
             const string& dbname,
             BSONObj& cmdObj,
             int,
             string& errmsg,
             BSONObjBuilder& result) {
        bool all = *cmdObj.firstElement().valuestrsafe() == '*';

        int before = result.len();

        const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap();
        for (ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i) {
            if (all || cmdObj.hasElement(i->first.c_str())) {
                i->second->append(txn, result, i->second->name());
            }
        }

        if (before == result.len()) {
            errmsg = "no option found to get";
            return false;
        }
        return true;
    }
Beispiel #26
0
        void doWork() {
            if ( !theReplSet ) {
                log(2) << "theReplSet not initialized yet, skipping health poll this round" << rsLog;
                return;
            }

            HeartbeatInfo mem = m;
            HeartbeatInfo old = mem;
            try {
                BSONObj info;
                int theirConfigVersion = -10000;

                Timer timer;

                bool ok = requestHeartbeat(theReplSet->name(), theReplSet->selfFullName(), h.toString(), info, theReplSet->config().version, theirConfigVersion);
                
                mem.ping = (unsigned int)timer.micros();

                time_t before = timer.startTime() / 1000000;
                // we set this on any response - we don't get this far if
                // couldn't connect because exception is thrown
                time_t after = mem.lastHeartbeat = before + (mem.ping / 1000000);
                
                if ( info["time"].isNumber() ) {
                    long long t = info["time"].numberLong();
                    if( t > after )
                        mem.skew = (int) (t - after);
                    else if( t < before )
                        mem.skew = (int) (t - before); // negative
                }
                else {
                    // it won't be there if remote hasn't initialized yet
                    if( info.hasElement("time") )
                        warning() << "heatbeat.time isn't a number: " << info << endl;
                    mem.skew = INT_MIN;
                }

                {
                    be state = info["state"];
                    if( state.ok() )
                        mem.hbstate = MemberState(state.Int());
                }
                if( ok ) {
                    if( mem.upSince == 0 ) {
                        log() << "replSet info " << h.toString() << " is up" << rsLog;
                        mem.upSince = mem.lastHeartbeat;
                    }
                    mem.health = 1.0;
                    mem.lastHeartbeatMsg = info["hbmsg"].String();
                    if( info.hasElement("opTime") )
                        mem.opTime = info["opTime"].Date();

                    be cfg = info["config"];
                    if( cfg.ok() ) {
                        // received a new config
                        boost::function<void()> f =
                            boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
                        theReplSet->mgr->send(f);
                    }
                }
                else {
                    down(mem, info.getStringField("errmsg"));
                }
            }
            catch(DBException& e) {
                down(mem, e.what());
            }
            catch(...) {
                down(mem, "something unusual went wrong");
            }
            m = mem;

            theReplSet->mgr->send( boost::bind(&ReplSet::msgUpdateHBInfo, theReplSet, mem) );

            static time_t last = 0;
            time_t now = time(0);
            bool changed = mem.changed(old);
            if( changed ) {
                if( old.hbstate != mem.hbstate )
                    log() << "replSet member " << h.toString() << ' ' << mem.hbstate.toString() << rsLog;
            }
            if( changed || now-last>4 ) {
                last = now;
                theReplSet->mgr->send( boost::bind(&Manager::msgCheckNewState, theReplSet->mgr) );
            }
        }
Beispiel #27
0
    /** Note: if the object shrinks a lot, we don't free up space, we leave extra at end of the record.
     */
    const DiskLoc DataFileMgr::updateRecord(
        const char *ns,
        Collection* collection,
        Record *toupdate, const DiskLoc& dl,
        const char *_buf, int _len, OpDebug& debug,  bool god) {

        dassert( toupdate == dl.rec() );

        BSONObj objOld = BSONObj::make(toupdate);
        BSONObj objNew(_buf);
        DEV verify( objNew.objsize() == _len );
        DEV verify( objNew.objdata() == _buf );

        if( !objNew.hasElement("_id") && objOld.hasElement("_id") ) {
            /* add back the old _id value if the update removes it.  Note this implementation is slow
               (copies entire object multiple times), but this shouldn't happen often, so going for simple
               code, not speed.
            */
            BSONObjBuilder b;
            BSONElement e;
            verify( objOld.getObjectID(e) );
            b.append(e); // put _id first, for best performance
            b.appendElements(objNew);
            objNew = b.obj();
        }

        NamespaceString nsstring(ns);
        if (nsstring.coll() == "system.users") {
            V2UserDocumentParser parser;
            uassertStatusOK(parser.checkValidUserDocument(objNew));
        }

        uassert( 13596 , str::stream() << "cannot change _id of a document old:" << objOld << " new:" << objNew,
                objNew["_id"] == objOld["_id"]);

        /* duplicate key check. we descend the btree twice - once for this check, and once for the actual inserts, further
           below.  that is suboptimal, but it's pretty complicated to do it the other way without rollbacks...
        */
        OwnedPointerVector<UpdateTicket> updateTickets;
        updateTickets.mutableVector().resize(collection->details()->getTotalIndexCount());
        for (int i = 0; i < collection->details()->getTotalIndexCount(); ++i) {
            auto_ptr<IndexDescriptor> descriptor(CatalogHack::getDescriptor(collection->details(), i));
            auto_ptr<IndexAccessMethod> iam(CatalogHack::getIndex(descriptor.get()));
            InsertDeleteOptions options;
            options.logIfError = false;
            options.dupsAllowed = !(KeyPattern::isIdKeyPattern(descriptor->keyPattern())
                                    || descriptor->unique())
                                  || ignoreUniqueIndex(descriptor->getOnDisk());
            updateTickets.mutableVector()[i] = new UpdateTicket();
            Status ret = iam->validateUpdate(objOld, objNew, dl, options,
                                             updateTickets.mutableVector()[i]);

            if (Status::OK() != ret) {
                uasserted(ASSERT_ID_DUPKEY, "Update validation failed: " + ret.toString());
            }
        }

        if ( toupdate->netLength() < objNew.objsize() ) {
            // doesn't fit.  reallocate -----------------------------------------------------
            moveCounter.increment();
            uassert( 10003,
                     "failing update: objects in a capped ns cannot grow",
                     !(collection && collection->details()->isCapped()));
            collection->details()->paddingTooSmall();
            deleteRecord(ns, toupdate, dl);
            DiskLoc res = insert(ns, objNew.objdata(), objNew.objsize(), false, god);

            if (debug.nmoved == -1) // default of -1 rather than 0
                debug.nmoved = 1;
            else
                debug.nmoved += 1;

            return res;
        }

        collection->infoCache()->notifyOfWriteOp();
        collection->details()->paddingFits();

        debug.keyUpdates = 0;

        for (int i = 0; i < collection->details()->getTotalIndexCount(); ++i) {
            auto_ptr<IndexDescriptor> descriptor(CatalogHack::getDescriptor(collection->details(), i));
            auto_ptr<IndexAccessMethod> iam(CatalogHack::getIndex(descriptor.get()));
            int64_t updatedKeys;
            Status ret = iam->update(*updateTickets.vector()[i], &updatedKeys);
            if (Status::OK() != ret) {
                // This shouldn't happen unless something disastrous occurred.
                massert(16799, "update failed: " + ret.toString(), false);
            }
            debug.keyUpdates += updatedKeys;
        }

        //  update in place
        int sz = objNew.objsize();
        memcpy(getDur().writingPtr(toupdate->data(), sz), objNew.objdata(), sz);
        return dl;
    }
Beispiel #28
0
        Config::Config( const string& _dbname , const BSONObj& cmdObj ) {

            dbname = _dbname;
            ns = dbname + "." + cmdObj.firstElement().valuestr();

            verbose = cmdObj["verbose"].trueValue();

            uassert( 13602 , "outType is no longer a valid option" , cmdObj["outType"].eoo() );

            if ( cmdObj["out"].type() == String ) {
                finalShort = cmdObj["out"].String();
                outType = REPLACE;
            }
            else if ( cmdObj["out"].type() == Object ) {
                BSONObj o = cmdObj["out"].embeddedObject();

                BSONElement e = o.firstElement();
                string t = e.fieldName();

                if ( t == "normal" || t == "replace" ) {
                    outType = REPLACE;
                    finalShort = e.String();
                }
                else if ( t == "merge" ) {
                    outType = MERGE;
                    finalShort = e.String();
                }
                else if ( t == "reduce" ) {
                    outType = REDUCE;
                    finalShort = e.String();
                }
                else if ( t == "inline" ) {
                    outType = INMEMORY;
                }
                else {
                    uasserted( 13522 , str::stream() << "unknown out specifier [" << t << "]" );
                }

                if (o.hasElement("db")) {
                    outDB = o["db"].String();
                }
            }
            else {
                uasserted( 13606 , "'out' has to be a string or an object" );
            }

            if ( outType != INMEMORY ) { // setup names
                tempLong = str::stream() << (outDB.empty() ? dbname : outDB) << ".tmp.mr." << cmdObj.firstElement().String() << "_" << finalShort << "_" << JOB_NUMBER++;

                incLong = tempLong + "_inc";

                finalLong = str::stream() << (outDB.empty() ? dbname : outDB) << "." << finalShort;
            }

            {
                // scope and code

                if ( cmdObj["scope"].type() == Object )
                    scopeSetup = cmdObj["scope"].embeddedObjectUserCheck();

                mapper.reset( new JSMapper( cmdObj["map"] ) );
                reducer.reset( new JSReducer( cmdObj["reduce"] ) );
                if ( cmdObj["finalize"].type() && cmdObj["finalize"].trueValue() )
                    finalizer.reset( new JSFinalizer( cmdObj["finalize"] ) );

                if ( cmdObj["mapparams"].type() == Array ) {
                    mapParams = cmdObj["mapparams"].embeddedObjectUserCheck();
                }

            }

            {
                // query options
                BSONElement q = cmdObj["query"];
                if ( q.type() == Object )
                    filter = q.embeddedObjectUserCheck();
                else
                    uassert( 13608 , "query has to be blank or an Object" , ! q.trueValue() );


                BSONElement s = cmdObj["sort"];
                if ( s.type() == Object )
                    sort = s.embeddedObjectUserCheck();
                else
                    uassert( 13609 , "sort has to be blank or an Object" , ! s.trueValue() );

                if ( cmdObj["limit"].isNumber() )
                    limit = cmdObj["limit"].numberLong();
                else
                    limit = 0;
            }
        }
Beispiel #29
0
        void up(const BSONObj& info, HeartbeatInfo& mem, bool* needsNewStateChecked) {
            HeartbeatInfo::numPings++;
            mem.authIssue = false;

            if( mem.upSince == 0 ) {
                log() << "replSet member " << h.toString() << " is up" << rsLog;
                mem.upSince = mem.lastHeartbeat;
            }
            mem.health = 1.0;
            mem.lastHeartbeatMsg = info["hbmsg"].String();
            if (info.hasElement("syncingTo")) {
                mem.syncingTo = info["syncingTo"].String();
            }
            if( info.hasElement("opTime") ) {
                mem.opTime = info["opTime"].Date();
            }
            if ( info.hasElement("GTID")) {
                mem.gtid = getGTIDFromBSON("GTID", info);
            }
            if ( info.hasElement("lastUnappliedGTID")) {
                mem.lastUnappliedGTID = getGTIDFromBSON("lastUnappliedGTID", info);
            }
            if ( info.hasElement("minLiveGTID")) {
                mem.minLiveGTID= getGTIDFromBSON("minLiveGTID", info);
            }
            if ( info.hasElement("minUnappliedGTID")) {
                mem.minUnappliedGTID= getGTIDFromBSON("minUnappliedGTID", info);
            }
            if ( info.hasElement("oplogVersion")) {
                mem.oplogVersion = info["oplogVersion"].numberLong();
            }
            else {
                mem.oplogVersion = 0;
            }
            // for "highest known primary"
            if ( info.hasElement("hkp")) {
                mem.highestKnownPrimaryInSet = info["hkp"].numberLong();
                // if the highest known primary across the replica set has changed,
                // communicate that to the caller so that Manager::msgCheckNewState
                // eventually gets called
                *needsNewStateChecked = theReplSet->handleHighestKnownPrimaryOfMember(mem.highestKnownPrimaryInSet);
            }
            else {
                mem.highestKnownPrimaryInSet = 0;
            }
            // see if this member is in the electable set
            if( info["e"].eoo() ) {
                // for backwards compatibility
                const Member *member = theReplSet->findById(mem.id());
                if (member && member->config().potentiallyHot()) {
                    theReplSet->addToElectable(mem.id());
                }
                else {
                    theReplSet->rmFromElectable(mem.id());
                }
            }
            // add this server to the electable set if it is within 10
            // seconds of the latest optime we know of
            else if( info["e"].trueValue() &&
                     mem.opTime + 10000 >= (theReplSet->gtidManager ? theReplSet->gtidManager->getCurrTimestamp() : 0)) 
            {
                unsigned lastOp = theReplSet->lastOtherOpTime();
                if (lastOp > 0 && mem.opTime + 10000 >= lastOp) {
                    theReplSet->addToElectable(mem.id());
                }
            }
            else {
                theReplSet->rmFromElectable(mem.id());
            }

            be cfg = info["config"];
            if( cfg.ok() ) {
                // received a new config
                boost::function<void()> f =
                    boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
                theReplSet->mgr->send(f);
            }
        }
Beispiel #30
0
        bool _requestHeartbeat(HeartbeatInfo& mem, BSONObj& info, int& theirConfigVersion) {
            {
                ScopedConn conn(h.toString());
                conn.setTimeout(_timeout);
                if (tries++ % threshold == (threshold - 1)) {
                    conn.reconnect();
                }
            }

            Timer timer;
            time_t before = curTimeMicros64() / 1000000;

            bool ok = tryHeartbeat(&info, &theirConfigVersion);

            mem.ping = static_cast<unsigned int>(timer.millis());
            time_t totalSecs = mem.ping / 1000;

            // if that didn't work and we have more time, lower timeout and try again
            if (!ok && totalSecs < _timeout) {
                log() << "replset info " << h.toString() << " heartbeat failed, retrying" << rsLog;

                // lower timeout to remaining ping time
                {
                    ScopedConn conn(h.toString());
                    conn.setTimeout(_timeout - totalSecs);
                }

                int checkpoint = timer.millis();
                timer.reset();
                ok = tryHeartbeat(&info, &theirConfigVersion);
                mem.ping = static_cast<unsigned int>(timer.millis());
                totalSecs = (checkpoint + mem.ping)/1000;

                // set timeout back to default
                {
                    ScopedConn conn(h.toString());
                    conn.setTimeout(_timeout);
                }
            }

            // we set this on any response - we don't get this far if
            // couldn't connect because exception is thrown
            time_t after = mem.lastHeartbeat = before + totalSecs;

            if ( info["time"].isNumber() ) {
                long long t = info["time"].numberLong();
                if( t > after )
                    mem.skew = (int) (t - after);
                else if( t < before )
                    mem.skew = (int) (t - before); // negative
            }
            else {
                // it won't be there if remote hasn't initialized yet
                if( info.hasElement("time") )
                    warning() << "heatbeat.time isn't a number: " << info << endl;
                mem.skew = INT_MIN;
            }

            {
                be state = info["state"];
                if( state.ok() )
                    mem.hbstate = MemberState(state.Int());
            }

            if (info.hasField("stateDisagreement") && info["stateDisagreement"].trueValue()) {
                log() << "replset info " << h.toString() << " thinks that we are down" << endl;
            }

            return ok;
        }