virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { BSONObj fromToken = cmdObj.getObjectField("finishCloneCollection"); if ( fromToken.isEmpty() ) { errmsg = "missing finishCloneCollection finishToken spec"; return false; } string fromhost = fromToken.getStringField( "fromhost" ); if ( fromhost.empty() ) { errmsg = "missing fromhost spec"; return false; } string collection = fromToken.getStringField("collection"); if ( collection.empty() ) { errmsg = "missing collection spec"; return false; } BSONObj query = fromToken.getObjectField("query"); if ( query.isEmpty() ) { query = BSONObj(); } long long cursorId = 0; BSONElement cursorIdToken = fromToken.getField( "cursorId" ); if ( cursorIdToken.type() == Date ) { cursorId = cursorIdToken.date(); } setClient( collection.c_str() ); log() << "finishCloneCollection. db:" << ns << " collection:" << collection << " from: " << fromhost << " query: " << query << endl; Cloner c; return c.finishCloneCollection( fromhost.c_str(), collection.c_str(), query, cursorId, errmsg ); }
void report() const { const OpTime &maxOpTimeSynced = _player->maxOpTimeSynced(); LOG(0) << "synced up to " << fmtOpTime(maxOpTimeSynced); if (!_rconn) { LOG(0) << endl; return; } Query lastQuery; lastQuery.sort("$natural", -1); BSONObj lastFields = BSON("ts" << 1); BSONObj lastObj = _rconn->conn().findOne(_oplogns, lastQuery, &lastFields); BSONElement tsElt = lastObj["ts"]; if (!tsElt.ok()) { warning() << "couldn't find last oplog entry on remote host" << endl; LOG(0) << endl; return; } OpTime lastOpTime = OpTime(tsElt.date()); LOG(0) << ", source has up to " << fmtOpTime(lastOpTime); if (maxOpTimeSynced == lastOpTime) { LOG(0) << ", fully synced." << endl; } else { int diff = lastOpTime.getSecs() - maxOpTimeSynced.getSecs(); if (diff > 0) { LOG(0) << ", " << (lastOpTime.getSecs() - maxOpTimeSynced.getSecs()) << " seconds behind source." << endl; } else { LOG(0) << ", less than 1 second behind source." << endl; } } _reportingTimer.reset(); }
StatusWith<DistLockCatalog::ServerInfo> DistLockCatalogImpl::getServerInfo(OperationContext* txn) { auto resultStatus = _client->getConfigShard()->runCommand(txn, kReadPref, "admin", BSON("serverStatus" << 1), Shard::kDefaultConfigCommandTimeout, Shard::RetryPolicy::kIdempotent); if (!resultStatus.isOK()) { return resultStatus.getStatus(); } if (!resultStatus.getValue().commandStatus.isOK()) { return resultStatus.getValue().commandStatus; } BSONObj responseObj(std::move(resultStatus.getValue().response)); BSONElement localTimeElem; auto localTimeStatus = bsonExtractTypedField(responseObj, kLocalTimeField, Date, &localTimeElem); if (!localTimeStatus.isOK()) { return {ErrorCodes::UnsupportedFormat, localTimeStatus.reason()}; } auto electionIdStatus = extractElectionId(responseObj); if (!electionIdStatus.isOK()) { return {ErrorCodes::UnsupportedFormat, electionIdStatus.getStatus().reason()}; } return DistLockCatalog::ServerInfo(localTimeElem.date(), electionIdStatus.getValue()); }
StatusWith<MongosType> MongosType::fromBSON(const BSONObj& source) { MongosType mt; { std::string mtName; Status status = bsonExtractStringField(source, name.name(), &mtName); if (!status.isOK()) return status; mt._name = mtName; } { BSONElement mtPingElem; Status status = bsonExtractTypedField(source, ping.name(), BSONType::Date, &mtPingElem); if (!status.isOK()) return status; mt._ping = mtPingElem.date(); } { long long mtUptime; Status status = bsonExtractIntegerField(source, uptime.name(), &mtUptime); if (!status.isOK()) return status; mt._uptime = mtUptime; } { bool mtWaiting; Status status = bsonExtractBooleanField(source, waiting.name(), &mtWaiting); if (!status.isOK()) return status; mt._waiting = mtWaiting; } if (source.hasField(mongoVersion.name())) { std::string mtMongoVersion; Status status = bsonExtractStringField(source, mongoVersion.name(), &mtMongoVersion); if (!status.isOK()) return status; mt._mongoVersion = mtMongoVersion; } if (source.hasField(configVersion.name())) { long long mtConfigVersion; Status status = bsonExtractIntegerField(source, configVersion.name(), &mtConfigVersion); if (!status.isOK()) return status; mt._configVersion = mtConfigVersion; } return mt; }
void ReplSource::syncToTailOfRemoteLog() { string _ns = ns(); BSONObjBuilder b; if ( !only.empty() ) { b.appendRegex("ns", string("^") + only); } BSONObj last = oplogReader.findOne( _ns.c_str(), Query( b.done() ).sort( BSON( "$natural" << -1 ) ) ); if ( !last.isEmpty() ) { BSONElement ts = last.getField( "ts" ); massert( 10386 , "non Date ts found: " + last.toString(), ts.type() == Date || ts.type() == Timestamp ); syncedTo = OpTime( ts.date() ); } }
bool attemptQuery(int queryOptions) { BSONObj res; auto_ptr<DBClientCursor> cursor(_rconn->conn().query( _oplogns, QUERY("ts" << GTE << _player->maxOpTimeSynced()), 0, 0, &res, queryOptions)); if (!cursor->more()) { log() << "oplog query returned no results, sleeping 10 seconds..." << endl; sleepsecs(10); log() << "retrying" << endl; return true; } BSONObj firstObj = cursor->next(); { BSONElement tsElt = firstObj["ts"]; if (!tsElt.ok()) { log() << "oplog format error: " << firstObj << " missing 'ts' field." << endl; logPosition(); return false; } OpTime firstTime(tsElt.date()); if (firstTime != _player->maxOpTimeSynced()) { throw CantFindTimestamp(firstTime); } } report(); while (running && cursor->more()) { while (running && cursor->moreInCurrentBatch()) { BSONObj obj = cursor->next(); LOG(2) << obj << endl; bool ok = _player->processObj(obj); if (!ok) { logPosition(); return false; } } _player->flushInserts(); if (_reportingTimer.seconds() >= _reportingPeriod) { report(); } } return true; }
StatusWith<ShardingMetadata> ShardingMetadata::readFromMetadata(const BSONObj& metadataObj) { BSONElement smElem; auto smExtractStatus = bsonExtractTypedField(metadataObj, kGLEStatsFieldName, mongol::Object, &smElem); if (!smExtractStatus.isOK()) { return smExtractStatus; } if (smElem.embeddedObject().nFields() != 2) { return Status(ErrorCodes::InvalidOptions, str::stream() << "The $gleStats object can only have 2 fields, but got " << smElem.embeddedObject().toString()); } repl::OpTime opTime; const BSONElement opTimeElement = smElem.embeddedObject()[kGLEStatsLastOpTimeFieldName]; if (opTimeElement.eoo()) { return Status(ErrorCodes::NoSuchKey, "lastOpTime field missing"); } else if (opTimeElement.type() == bsonTimestamp) { opTime = repl::OpTime(opTimeElement.timestamp(), repl::OpTime::kUninitializedTerm); } else if (opTimeElement.type() == Date) { opTime = repl::OpTime(Timestamp(opTimeElement.date()), repl::OpTime::kUninitializedTerm); } else if (opTimeElement.type() == Object) { Status status = bsonExtractOpTimeField(smElem.embeddedObject(), kGLEStatsLastOpTimeFieldName, &opTime); if (!status.isOK()) { return status; } } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kGLEStatsLastOpTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(opTimeElement.type())); } BSONElement lastElectionIdElem; auto lastElectionIdExtractStatus = bsonExtractTypedField( smElem.embeddedObject(), kGLEStatsElectionIdFieldName, mongol::jstOID, &lastElectionIdElem); if (!lastElectionIdExtractStatus.isOK()) { return lastElectionIdExtractStatus; } return ShardingMetadata(opTime, lastElectionIdElem.OID()); }
StatusWith<DistLockCatalog::ServerInfo> DistLockCatalogImpl::getServerInfo() { auto targetStatus = _targeter->findHost(kReadPref); if (!targetStatus.isOK()) { return targetStatus.getStatus(); } auto resultStatus = _cmdRunner->runCommand(RemoteCommandRequest( targetStatus.getValue(), "admin", BSON("serverStatus" << 1))); if (!resultStatus.isOK()) { return resultStatus.getStatus(); } const RemoteCommandResponse& response = resultStatus.getValue(); BSONObj responseObj(response.data); auto cmdStatus = getStatusFromCommandResult(responseObj); if (!cmdStatus.isOK()) { return cmdStatus; } BSONElement localTimeElem; auto localTimeStatus = bsonExtractTypedField(responseObj, kLocalTimeField, Date, &localTimeElem); if (!localTimeStatus.isOK()) { return {ErrorCodes::UnsupportedFormat, localTimeStatus.reason()}; } auto electionIdStatus = extractElectionId(responseObj); if (!electionIdStatus.isOK()) { return {ErrorCodes::UnsupportedFormat, electionIdStatus.getStatus().reason()}; } return DistLockCatalog::ServerInfo(localTimeElem.date(), electionIdStatus.getValue()); }
unsigned long long getVersion( BSONElement e , string& errmsg ){ if ( e.eoo() ){ errmsg = "no version"; return 0; } if ( e.isNumberLong() ) return (unsigned long long)e.number64(); if ( e.isNumber() ) return (unsigned long long)e.number(); if ( e.type() == Date || e.type() == Timestamp ) return e.date(); errmsg = "version is not a numberic type"; return 0; }
FieldParser::FieldState FieldParser::extract(BSONElement elem, const BSONField<Date_t>& field, Date_t* out, string* errMsg) { if (elem.eoo()) { if (field.hasDefault()) { *out = field.getDefault(); return FIELD_DEFAULT; } else { return FIELD_NONE; } } if (elem.type() == Date) { *out = elem.date(); return FIELD_SET; } _genFieldErrMsg(elem, field, "date", errMsg); return FIELD_INVALID; }
jsval toval( const BSONElement& e ) { switch( e.type() ) { case EOO: case jstNULL: case Undefined: return JSVAL_NULL; case NumberDouble: case NumberInt: return toval( e.number() ); case Symbol: // TODO: should we make a special class for this case String: return toval( e.valuestr() ); case Bool: return e.boolean() ? JSVAL_TRUE : JSVAL_FALSE; case Object: { BSONObj embed = e.embeddedObject().getOwned(); return toval( &embed ); } case Array: { BSONObj embed = e.embeddedObject().getOwned(); if ( embed.isEmpty() ) { return OBJECT_TO_JSVAL( JS_NewArrayObject( _context , 0 , 0 ) ); } int n = embed.nFields(); JSObject * array = JS_NewArrayObject( _context , n , 0 ); assert( array ); jsval myarray = OBJECT_TO_JSVAL( array ); for ( int i=0; i<n; i++ ) { jsval v = toval( embed[i] ); assert( JS_SetElement( _context , array , i , &v ) ); } return myarray; } case jstOID: { OID oid = e.__oid(); JSObject * o = JS_NewObject( _context , &object_id_class , 0 , 0 ); setProperty( o , "str" , toval( oid.str().c_str() ) ); return OBJECT_TO_JSVAL( o ); } case RegEx: { const char * flags = e.regexFlags(); uintN flagNumber = 0; while ( *flags ) { switch ( *flags ) { case 'g': flagNumber |= JSREG_GLOB; break; case 'i': flagNumber |= JSREG_FOLD; break; case 'm': flagNumber |= JSREG_MULTILINE; break; //case 'y': flagNumber |= JSREG_STICKY; break; default: log() << "warning: unknown regex flag:" << *flags << endl; } flags++; } JSObject * r = JS_NewRegExpObject( _context , (char*)e.regex() , strlen( e.regex() ) , flagNumber ); assert( r ); return OBJECT_TO_JSVAL( r ); } case Code: { JSFunction * func = compileFunction( e.valuestr() ); return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); } case CodeWScope: { JSFunction * func = compileFunction( e.codeWScopeCode() ); BSONObj extraScope = e.codeWScopeObject(); if ( ! extraScope.isEmpty() ) { log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; } return OBJECT_TO_JSVAL( JS_GetFunctionObject( func ) ); } case Date: return OBJECT_TO_JSVAL( js_NewDateObjectMsec( _context , (jsdouble) e.date().millis ) ); case MinKey: return OBJECT_TO_JSVAL( JS_NewObject( _context , &minkey_class , 0 , 0 ) ); case MaxKey: return OBJECT_TO_JSVAL( JS_NewObject( _context , &maxkey_class , 0 , 0 ) ); case Timestamp: { JSObject * o = JS_NewObject( _context , ×tamp_class , 0 , 0 ); setProperty( o , "t" , toval( (double)(e.timestampTime()) ) ); setProperty( o , "i" , toval( (double)(e.timestampInc()) ) ); return OBJECT_TO_JSVAL( o ); } case NumberLong: { boost::uint64_t val = (boost::uint64_t)e.numberLong(); JSObject * o = JS_NewObject( _context , &numberlong_class , 0 , 0 ); setProperty( o , "floatApprox" , toval( (double)(boost::int64_t)( val ) ) ); if ( (boost::int64_t)val != (boost::int64_t)(double)(boost::int64_t)( val ) ) { // using 2 doubles here instead of a single double because certain double // bit patterns represent undefined values and sm might trash them setProperty( o , "top" , toval( (double)(boost::uint32_t)( val >> 32 ) ) ); setProperty( o , "bottom" , toval( (double)(boost::uint32_t)( val & 0x00000000ffffffff ) ) ); } return OBJECT_TO_JSVAL( o ); } case DBRef: { JSObject * o = JS_NewObject( _context , &dbpointer_class , 0 , 0 ); setProperty( o , "ns" , toval( e.dbrefNS() ) ); JSObject * oid = JS_NewObject( _context , &object_id_class , 0 , 0 ); setProperty( oid , "str" , toval( e.dbrefOID().str().c_str() ) ); setProperty( o , "id" , OBJECT_TO_JSVAL( oid ) ); return OBJECT_TO_JSVAL( o ); } case BinData: { JSObject * o = JS_NewObject( _context , &bindata_class , 0 , 0 ); int len; const char * data = e.binData( len ); assert( JS_SetPrivate( _context , o , new BinDataHolder( data ) ) ); setProperty( o , "len" , toval( len ) ); setProperty( o , "type" , toval( (int)e.binDataType() ) ); return OBJECT_TO_JSVAL( o ); } }
/* must be same type! */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; switch ( l.type() ) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: f = l.type() - r.type(); if ( f<0 ) return -1; return f==0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: case Date: if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); bool lNan = !( left <= numeric_limits< double >::max() && left >= -numeric_limits< double >::max() ); bool rNan = !( right <= numeric_limits< double >::max() && right >= -numeric_limits< double >::max() ); if ( lNan ) { if ( rNan ) { return 0; } else { return -1; } } else if ( rNan ) { return 1; } x = left - right; if ( x < 0 ) return -1; return x == 0 ? 0 : 1; } case jstOID: return memcmp(l.value(), r.value(), 12); case Code: case Symbol: case String: /* todo: utf version */ return strcmp(l.valuestr(), r.valuestr()); case Object: case Array: return l.embeddedObject().woCompare( r.embeddedObject() ); case DBRef: case BinData: { int lsz = l.valuesize(); int rsz = r.valuesize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if ( c ) return c; return strcmp(l.regexFlags(), r.regexFlags()); } default: out() << "compareElementValues: bad type " << (int) l.type() << endl; assert(false); } return -1; }
Local<v8::Object> mongoToV8( BSONObj & m , bool array ){ Local<v8::Object> o; if ( array ) o = v8::Array::New(); else o = v8::Object::New(); mongo::BSONObj sub; for ( BSONObjIterator i(m); i.more(); ) { BSONElement f = i.next(); if ( f.eoo() ) break; Local<Value> v; switch ( f.type() ){ case mongo::Code: cout << "warning, code saved in database just turned into string right now" << endl; case mongo::String: o->Set( v8::String::New( f.fieldName() ) , v8::String::New( f.valuestr() ) ); break; case mongo::jstOID: { v8::Function * idCons = getObjectIdCons(); v8::Handle<v8::Value> argv[1]; argv[0] = v8::String::New( f.__oid().str().c_str() ); o->Set( v8::String::New( f.fieldName() ) , idCons->NewInstance( 1 , argv ) ); break; } case mongo::NumberDouble: case mongo::NumberInt: o->Set( v8::String::New( f.fieldName() ) , v8::Number::New( f.number() ) ); break; case mongo::Array: case mongo::Object: sub = f.embeddedObject(); o->Set( v8::String::New( f.fieldName() ) , mongoToV8( sub , f.type() == mongo::Array ) ); break; case mongo::Date: o->Set( v8::String::New( f.fieldName() ) , v8::Date::New( f.date() ) ); break; case mongo::Bool: o->Set( v8::String::New( f.fieldName() ) , v8::Boolean::New( f.boolean() ) ); break; case mongo::jstNULL: o->Set( v8::String::New( f.fieldName() ) , v8::Null() ); break; case mongo::RegEx: { v8::Function * regex = getNamedCons( "RegExp" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.regex() ); argv[1] = v8::String::New( f.regexFlags() ); o->Set( v8::String::New( f.fieldName() ) , regex->NewInstance( 2 , argv ) ); break; } case mongo::BinData: { Local<v8::Object> b = v8::Object::New(); int len; f.binData( len ); b->Set( v8::String::New( "subtype" ) , v8::Number::New( f.binDataType() ) ); b->Set( v8::String::New( "length" ) , v8::Number::New( len ) ); o->Set( v8::String::New( f.fieldName() ) , b ); break; }; case mongo::Timestamp: { Local<v8::Object> sub = v8::Object::New(); sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) ); sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) ); o->Set( v8::String::New( f.fieldName() ) , sub ); break; } default: cout << "can't handle type: "; cout << f.type() << " "; cout << f.toString(); cout << endl; break; } } return o; }
void BSONComparatorInterfaceBase<T>::hashCombineBSONElement( size_t& hash, BSONElement elemToHash, bool considerFieldName, const StringData::ComparatorInterface* stringComparator) { boost::hash_combine(hash, elemToHash.canonicalType()); const StringData fieldName = elemToHash.fieldNameStringData(); if (considerFieldName && !fieldName.empty()) { SimpleStringDataComparator::kInstance.hash_combine(hash, fieldName); } switch (elemToHash.type()) { // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: case mongo::jstNULL: case mongo::MaxKey: case mongo::MinKey: // These are valueless types break; case mongo::Bool: boost::hash_combine(hash, elemToHash.boolean()); break; case mongo::bsonTimestamp: boost::hash_combine(hash, elemToHash.timestamp().asULL()); break; case mongo::Date: boost::hash_combine(hash, elemToHash.date().asInt64()); break; case mongo::NumberDecimal: { const Decimal128 dcml = elemToHash.numberDecimal(); if (dcml.toAbs().isGreater(Decimal128(std::numeric_limits<double>::max(), Decimal128::kRoundTo34Digits, Decimal128::kRoundTowardZero)) && !dcml.isInfinite() && !dcml.isNaN()) { // Normalize our decimal to force equivalent decimals // in the same cohort to hash to the same value Decimal128 dcmlNorm(dcml.normalize()); boost::hash_combine(hash, dcmlNorm.getValue().low64); boost::hash_combine(hash, dcmlNorm.getValue().high64); break; } // Else, fall through and convert the decimal to a double and hash. // At this point the decimal fits into the range of doubles, is infinity, or is NaN, // which doubles have a cheaper representation for. } case mongo::NumberDouble: case mongo::NumberLong: case mongo::NumberInt: { // This converts all numbers to doubles, which ignores the low-order bits of // NumberLongs > 2**53 and precise decimal numbers without double representations, // but that is ok since the hash will still be the same for equal numbers and is // still likely to be different for different numbers. (Note: this issue only // applies for decimals when they are outside of the valid double range. See // the above case.) // SERVER-16851 const double dbl = elemToHash.numberDouble(); if (std::isnan(dbl)) { boost::hash_combine(hash, std::numeric_limits<double>::quiet_NaN()); } else { boost::hash_combine(hash, dbl); } break; } case mongo::jstOID: elemToHash.__oid().hash_combine(hash); break; case mongo::String: { if (stringComparator) { stringComparator->hash_combine(hash, elemToHash.valueStringData()); } else { SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); } break; } case mongo::Code: case mongo::Symbol: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); break; case mongo::Object: case mongo::Array: hashCombineBSONObj(hash, elemToHash.embeddedObject(), true, // considerFieldName stringComparator); break; case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.value(), elemToHash.valuesize())); break; case mongo::RegEx: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regex()); SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regexFlags()); break; case mongo::CodeWScope: { SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.codeWScopeCode(), elemToHash.codeWScopeCodeLen())); hashCombineBSONObj(hash, elemToHash.codeWScopeObject(), true, // considerFieldName &SimpleStringDataComparator::kInstance); break; } } }
// fromBSON to Key format KeyV1Owned::KeyV1Owned(const BSONObj& obj) { BSONObj::iterator i(obj); assert( i.more() ); unsigned char bits = 0; while( 1 ) { BSONElement e = i.next(); if( i.more() ) bits |= cHASMORE; switch( e.type() ) { case MinKey: b.appendUChar(cminkey|bits); break; case jstNULL: b.appendUChar(cnull|bits); break; case MaxKey: b.appendUChar(cmaxkey|bits); break; case Bool: b.appendUChar( (e.boolean()?ctrue:cfalse) | bits ); break; case jstOID: b.appendUChar(coid|bits); b.appendBuf(&e.__oid(), sizeof(OID)); break; case BinData: { int t = e.binDataType(); // 0-7 and 0x80 to 0x87 are supported by Key if( (t & 0x78) == 0 && t != ByteArrayDeprecated ) { int len; const char * d = e.binData(len); int code = BinDataLengthToCode[len]; if( code >= 0 ) { if( t >= 128 ) t = (t-128) | 0x08; dassert( (code&t) == 0 ); b.appendUChar( cbindata|bits ); b.appendUChar( code | t ); b.appendBuf(d, len); break; } } traditional(obj); return; } case Date: b.appendUChar(cdate|bits); b.appendStruct(e.date()); break; case String: { b.appendUChar(cstring|bits); // note we do not store the terminating null, to save space. unsigned x = (unsigned) e.valuestrsize() - 1; if( x > 255 ) { traditional(obj); return; } b.appendUChar(x); b.appendBuf(e.valuestr(), x); break; } case NumberInt: b.appendUChar(cint|bits); b.appendNum((double) e._numberInt()); break; case NumberLong: { long long n = e._numberLong(); double d = (double) n; if( d != n ) { traditional(obj); return; } b.appendUChar(clong|bits); b.appendNum(d); break; } case NumberDouble: { double d = e._numberDouble(); bool nan = !( d <= numeric_limits< double >::max() && d >= -numeric_limits< double >::max() ); if( !nan ) { b.appendUChar(cdouble|bits); b.appendNum(d); break; } // else fall through and return a traditional BSON obj so our compressed keys need not check for nan } default: // if other types involved, store as traditional BSON traditional(obj); return; } if( !i.more() ) break; bits = 0; } _keyData = (const unsigned char *) b.buf(); dassert( b.len() == dataSize() ); // check datasize method is correct dassert( (*_keyData & cNOTUSED) == 0 ); }
Handle<v8::Value> mongoToV8Element( const BSONElement &f ) { Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New(); internalFieldObjects->SetInternalFieldCount( 1 ); switch ( f.type() ){ case mongo::Code: return newFunction( f.valuestr() ); case CodeWScope: if ( f.codeWScopeObject().isEmpty() ) log() << "warning: CodeWScope doesn't transfer to db.eval" << endl; return newFunction( f.codeWScopeCode() ); case mongo::String: return v8::String::New( f.valuestr() ); case mongo::jstOID: return newId( f.__oid() ); case mongo::NumberDouble: case mongo::NumberInt: return v8::Number::New( f.number() ); case mongo::Array: case mongo::Object: return mongoToV8( f.embeddedObject() , f.type() == mongo::Array ); case mongo::Date: return v8::Date::New( f.date() ); case mongo::Bool: return v8::Boolean::New( f.boolean() ); case mongo::EOO: case mongo::jstNULL: case mongo::Undefined: // duplicate sm behavior return v8::Null(); case mongo::RegEx: { v8::Function * regex = getNamedCons( "RegExp" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.regex() ); argv[1] = v8::String::New( f.regexFlags() ); return regex->NewInstance( 2 , argv ); break; } case mongo::BinData: { int len; const char *data = f.binData( len ); v8::Function* binData = getNamedCons( "BinData" ); v8::Handle<v8::Value> argv[3]; argv[0] = v8::Number::New( len ); argv[1] = v8::Number::New( f.binDataType() ); argv[2] = v8::String::New( data, len ); return binData->NewInstance( 3, argv ); }; case mongo::Timestamp: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) ); sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::NumberLong: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); unsigned long long val = f.numberLong(); v8::Function* numberLong = getNamedCons( "NumberLong" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::Integer::New( val >> 32 ); argv[1] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ); return numberLong->NewInstance( 2, argv ); } case mongo::MinKey: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::MaxKey: { Local<v8::Object> sub = internalFieldObjects->NewInstance(); sub->Set( v8::String::New( "$MaxKey" ), v8::Boolean::New( true ) ); sub->SetInternalField( 0, v8::Uint32::New( f.type() ) ); return sub; } case mongo::DBRef: { v8::Function* dbPointer = getNamedCons( "DBPointer" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.dbrefNS() ); argv[1] = newId( f.dbrefOID() ); return dbPointer->NewInstance(2, argv); } default: cout << "can't handle type: "; cout << f.type() << " "; cout << f.toString(); cout << endl; break; } return v8::Undefined(); }
bool ReplSource::handleDuplicateDbName( const BSONObj &op, const char *ns, const char *db ) { if ( dbHolder()._isLoaded( ns, dbpath ) ) { // Database is already present. return true; } BSONElement ts = op.getField( "ts" ); if ( ( ts.type() == Date || ts.type() == Timestamp ) && ___databaseIgnorer.ignoreAt( db, ts.date() ) ) { // Database is ignored due to a previous indication that it is // missing from master after optime "ts". return false; } if ( Database::duplicateUncasedName( false, db, dbpath ).empty() ) { // No duplicate database names are present. return true; } OpTime lastTime; bool dbOk = false; { dbtemprelease release; // We always log an operation after executing it (never before), so // a database list will always be valid as of an oplog entry generated // before it was retrieved. BSONObj last = oplogReader.findOne( this->ns().c_str(), Query().sort( BSON( "$natural" << -1 ) ) ); if ( !last.isEmpty() ) { BSONElement ts = last.getField( "ts" ); massert( 14032, "Invalid 'ts' in remote log", ts.type() == Date || ts.type() == Timestamp ); lastTime = OpTime( ts.date() ); } BSONObj info; bool ok = oplogReader.conn()->runCommand( "admin", BSON( "listDatabases" << 1 ), info ); massert( 14033, "Unable to get database list", ok ); BSONObjIterator i( info.getField( "databases" ).embeddedObject() ); while( i.more() ) { BSONElement e = i.next(); const char * name = e.embeddedObject().getField( "name" ).valuestr(); if ( strcasecmp( name, db ) != 0 ) continue; if ( strcmp( name, db ) == 0 ) { // The db exists on master, still need to check that no conflicts exist there. dbOk = true; continue; } // The master has a db name that conflicts with the requested name. dbOk = false; break; } } if ( !dbOk ) { ___databaseIgnorer.doIgnoreUntilAfter( db, lastTime ); incompleteCloneDbs.erase(db); addDbNextPass.erase(db); return false; } // Check for duplicates again, since we released the lock above. set< string > duplicates; Database::duplicateUncasedName( false, db, dbpath, &duplicates ); // The database is present on the master and no conflicting databases // are present on the master. Drop any local conflicts. for( set< string >::const_iterator i = duplicates.begin(); i != duplicates.end(); ++i ) { ___databaseIgnorer.doIgnoreUntilAfter( *i, lastTime ); incompleteCloneDbs.erase(*i); addDbNextPass.erase(*i); Client::Context ctx(*i); dropDatabase(*i); } massert( 14034, "Duplicate database names present after attempting to delete duplicates", Database::duplicateUncasedName( false, db, dbpath ).empty() ); return true; }
bool BatchedCommandResponse::parseBSON(const BSONObj& source, string* errMsg) { clear(); std::string dummy; if (!errMsg) errMsg = &dummy; FieldParser::FieldState fieldState; fieldState = FieldParser::extractNumber(source, ok, &_ok, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isOkSet = fieldState == FieldParser::FIELD_SET; fieldState = FieldParser::extract(source, errCode, &_errCode, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isErrCodeSet = fieldState == FieldParser::FIELD_SET; fieldState = FieldParser::extract(source, errMessage, &_errMessage, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isErrMessageSet = fieldState == FieldParser::FIELD_SET; // We're using appendNumber on generation so we'll try a smaller type // (int) first and then fall back to the original type (long long). BSONField<int> fieldN(n()); int tempN; fieldState = FieldParser::extract(source, fieldN, &tempN, errMsg); if (fieldState == FieldParser::FIELD_INVALID) { // try falling back to a larger type fieldState = FieldParser::extract(source, n, &_n, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isNSet = fieldState == FieldParser::FIELD_SET; } else if (fieldState == FieldParser::FIELD_SET) { _isNSet = true; _n = tempN; } // We're using appendNumber on generation so we'll try a smaller type // (int) first and then fall back to the original type (long long). BSONField<int> fieldNModified(nModified()); int intNModified; fieldState = FieldParser::extract(source, fieldNModified, &intNModified, errMsg); if (fieldState == FieldParser::FIELD_INVALID) { // try falling back to a larger type fieldState = FieldParser::extract(source, nModified, &_nModified, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isNModifiedSet = fieldState == FieldParser::FIELD_SET; } else if (fieldState == FieldParser::FIELD_SET) { _isNModifiedSet = true; _nModified = intNModified; } std::vector<BatchedUpsertDetail*>* tempUpsertDetails = NULL; fieldState = FieldParser::extract(source, upsertDetails, &tempUpsertDetails, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _upsertDetails.reset(tempUpsertDetails); const BSONElement opTimeElement = source["opTime"]; _isLastOpSet = true; if (opTimeElement.eoo()) { _isLastOpSet = false; } else if (opTimeElement.type() == bsonTimestamp) { _lastOp = repl::OpTime(opTimeElement.timestamp(), repl::OpTime::kUninitializedTerm); } else if (opTimeElement.type() == Date) { _lastOp = repl::OpTime(Timestamp(opTimeElement.date()), repl::OpTime::kUninitializedTerm); } else if (opTimeElement.type() == Object) { Status status = bsonExtractOpTimeField(source, "opTime", &_lastOp); if (!status.isOK()) { return false; } } else { return false; } fieldState = FieldParser::extract(source, electionId, &_electionId, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _isElectionIdSet = fieldState == FieldParser::FIELD_SET; std::vector<WriteErrorDetail*>* tempErrDetails = NULL; fieldState = FieldParser::extract(source, writeErrors, &tempErrDetails, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _writeErrorDetails.reset(tempErrDetails); WCErrorDetail* wcError = NULL; fieldState = FieldParser::extract(source, writeConcernError, &wcError, errMsg); if (fieldState == FieldParser::FIELD_INVALID) return false; _wcErrDetails.reset(wcError); return true; }
Handle<v8::Value> mongoToV8Element( const BSONElement &f ) { assert( !f.eoo() ); switch ( f.type() ){ case mongo::Code: cout << "warning, code saved in database just turned into string right now" << endl; case mongo::String: return v8::String::New( f.valuestr() ); case mongo::jstOID: { v8::Function * idCons = getObjectIdCons(); v8::Handle<v8::Value> argv[1]; argv[0] = v8::String::New( f.__oid().str().c_str() ); return idCons->NewInstance( 1 , argv ); } case mongo::NumberDouble: case mongo::NumberInt: return v8::Number::New( f.number() ); case mongo::Array: case mongo::Object: return mongoToV8( f.embeddedObject() , f.type() == mongo::Array ); case mongo::Date: return v8::Date::New( f.date() ); case mongo::Bool: return v8::Boolean::New( f.boolean() ); case mongo::jstNULL: return v8::Null(); case mongo::RegEx: { v8::Function * regex = getNamedCons( "RegExp" ); v8::Handle<v8::Value> argv[2]; argv[0] = v8::String::New( f.regex() ); argv[1] = v8::String::New( f.regexFlags() ); return regex->NewInstance( 2 , argv ); break; } case mongo::BinData: { Local<v8::Object> b = v8::Object::New(); int len; f.binData( len ); b->Set( v8::String::New( "subtype" ) , v8::Number::New( f.binDataType() ) ); b->Set( v8::String::New( "length" ) , v8::Number::New( len ) ); return b; }; case mongo::Timestamp: { Local<v8::Object> sub = v8::Object::New(); sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) ); sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) ); return sub; } case mongo::MinKey: // TODO: make a special type return v8::String::New( "MinKey" ); case mongo::MaxKey: // TODO: make a special type return v8::String::New( "MaxKey" ); case mongo::Undefined: return v8::Undefined(); default: cout << "can't handle type: "; cout << f.type() << " "; cout << f.toString(); cout << endl; break; } return v8::Undefined(); }
StatusWith<MongosType> MongosType::fromBSON(const BSONObj& source) { MongosType mt; { std::string mtName; Status status = bsonExtractStringField(source, name.name(), &mtName); if (!status.isOK()) return status; mt._name = mtName; } { BSONElement mtPingElem; Status status = bsonExtractTypedField(source, ping.name(), BSONType::Date, &mtPingElem); if (!status.isOK()) return status; mt._ping = mtPingElem.date(); } { long long mtUptime; Status status = bsonExtractIntegerField(source, uptime.name(), &mtUptime); if (!status.isOK()) return status; mt._uptime = mtUptime; } { bool mtWaiting; Status status = bsonExtractBooleanField(source, waiting.name(), &mtWaiting); if (!status.isOK()) return status; mt._waiting = mtWaiting; } if (source.hasField(mongoVersion.name())) { std::string mtMongoVersion; Status status = bsonExtractStringField(source, mongoVersion.name(), &mtMongoVersion); if (!status.isOK()) return status; mt._mongoVersion = mtMongoVersion; } if (source.hasField(configVersion.name())) { long long mtConfigVersion; Status status = bsonExtractIntegerField(source, configVersion.name(), &mtConfigVersion); if (!status.isOK()) return status; mt._configVersion = mtConfigVersion; } if (source.hasField(advisoryHostFQDNs.name())) { mt._advisoryHostFQDNs = std::vector<std::string>(); BSONElement array; Status status = bsonExtractTypedField(source, advisoryHostFQDNs.name(), Array, &array); if (!status.isOK()) return status; BSONObjIterator it(array.Obj()); while (it.more()) { BSONElement arrayElement = it.next(); if (arrayElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << advisoryHostFQDNs.name() << "\" array must be strings but found " << typeName(arrayElement.type())); } mt._advisoryHostFQDNs->push_back(arrayElement.String()); } } return mt; }
std::string jsonString(BSONElement &elem, JsonStringFormat format, bool includeFieldNames, int pretty, UUIDEncoding uuidEncoding) { BSONType t = elem.type(); int sign; if ( t == Undefined ) return "undefined"; stringstream s; if ( includeFieldNames ) s << '"' << escape( elem.fieldName() ) << "\" : "; switch ( elem.type() ) { case mongo::String: case Symbol: s << '"' << escape( string(elem.valuestr(), elem.valuestrsize()-1) ) << '"'; break; case NumberLong: s << "NumberLong(" << elem._numberLong() << ")"; break; case NumberInt: case NumberDouble: if ( elem.number() >= -numeric_limits< double >::max() && elem.number() <= numeric_limits< double >::max() ) { s.precision( 16 ); s << elem.number(); } else if ( mongo::isNaN(elem.number()) ) { s << "NaN"; } else if ( mongo::isInf(elem.number(), &sign) ) { s << ( sign == 1 ? "Infinity" : "-Infinity"); } else { StringBuilder ss; ss << "Number " << elem.number() << " cannot be represented in JSON"; string message = ss.str(); //massert( 10311 , message.c_str(), false ); } break; case mongo::Bool: s << ( elem.boolean() ? "true" : "false" ); break; case jstNULL: s << "null"; break; case Object: { BSONObj obj = elem.embeddedObject(); s << jsonString(obj, format, pretty, uuidEncoding); } break; case mongo::Array: { if ( elem.embeddedObject().isEmpty() ) { s << "[]"; break; } s << "[ "; BSONObjIterator i( elem.embeddedObject() ); BSONElement e = i.next(); if ( !e.eoo() ) { int count = 0; while ( 1 ) { if( pretty ) { s << '\n'; for( int x = 0; x < pretty; x++ ) s << " "; } if (strtol(e.fieldName(), 0, 10) > count) { s << "undefined"; } else { s << jsonString(e, format, false, pretty?pretty+1:0, uuidEncoding); e = i.next(); } count++; if ( e.eoo() ) { s << '\n'; for( int x = 0; x < pretty - 1; x++ ) s << " "; s << "]"; break; } s << ", "; } } //s << " ]"; break; } case DBRef: { mongo::OID *x = (mongo::OID *) (elem.valuestr() + elem.valuestrsize()); if ( format == TenGen ) s << "Dbref( "; else s << "{ \"$ref\" : "; s << '"' << elem.valuestr() << "\", "; if ( format != TenGen ) s << "\"$id\" : "; s << '"' << *x << "\" "; if ( format == TenGen ) s << ')'; else s << '}'; break; } case jstOID: if ( format == TenGen ) { s << "ObjectId("; } else { s << "{ \"$oid\" : "; } s << '"' << elem.__oid() << '"'; if ( format == TenGen ) { s << ")"; } else { s << " }"; } break; case BinData: { int len = *(int *)( elem.value() ); BinDataType type = BinDataType( *(char *)( (int *)( elem.value() ) + 1 ) ); if (type == mongo::bdtUUID || type == mongo::newUUID) { s << HexUtils::formatUuid(elem, uuidEncoding); break; } s << "{ \"$binary\" : \""; char *start = ( char * )( elem.value() ) + sizeof( int ) + 1; base64::encode( s , start , len ); s << "\", \"$type\" : \"" << hex; s.width( 2 ); s.fill( '0' ); s << type << dec; s << "\" }"; break; } case mongo::Date: if ( format == Strict ) s << "{ \"$date\" : "; else s << "ISODate("; if( pretty ) { Date_t d = elem.date(); long long ms = (long long) d.millis; boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); boost::posix_time::time_duration diff = boost::posix_time::millisec(ms); boost::posix_time::ptime time = epoch + diff; std::string timestr = miutil::isotimeString(time, true, true); s << '"' << timestr << '"'; /* if( d == 0 ) s << '0'; else //P s << '"' << elem.date().toString() << '"'; s << '"' << elem.date().millis << '"';*/ } else s << elem.date(); if ( format == Strict ) s << " }"; else s << ")"; break; case RegEx: if ( format == Strict ) { s << "{ \"$regex\" : \"" << escape( elem.regex() ); s << "\", \"$options\" : \"" << elem.regexFlags() << "\" }"; } else { s << "/" << escape( elem.regex() , true ) << "/"; // FIXME Worry about alpha order? for ( const char *f = elem.regexFlags(); *f; ++f ) { switch ( *f ) { case 'g': case 'i': case 'm': s << *f; default: break; } } } break; case CodeWScope: { BSONObj scope = elem.codeWScopeObject(); if ( ! scope.isEmpty() ) { s << "{ \"$code\" : " << elem._asCode() << " , " << " \"$scope\" : " << scope.jsonString() << " }"; break; } } case Code: s << elem._asCode(); break; case Timestamp: if ( format == TenGen ) { s << "Timestamp(" << ( elem.timestampTime() / 1000 ) << ", " << elem.timestampInc() << ")"; } else { s << "{ \"$timestamp\" : { \"t\" : " << ( elem.timestampTime() / 1000 ) << ", \"i\" : " << elem.timestampInc() << " } }"; } break; case MinKey: s << "{ \"$minKey\" : 1 }"; break; case MaxKey: s << "{ \"$maxKey\" : 1 }"; break; default: StringBuilder ss; ss << "Cannot create a properly formatted JSON string with " << "element: " << elem.toString() << " of type: " << elem.type(); string message = ss.str(); //massert( 10312 , message.c_str(), false ); } return s.str(); }
StatusWith<ChangeLogType> ChangeLogType::fromBSON(const BSONObj& source) { ChangeLogType changeLog; { std::string changeLogId; Status status = bsonExtractStringField(source, changeId.name(), &changeLogId); if (!status.isOK()) return status; changeLog._changeId = changeLogId; } { std::string changeLogServer; Status status = bsonExtractStringField(source, server.name(), &changeLogServer); if (!status.isOK()) return status; changeLog._server = changeLogServer; } { std::string changeLogShard; Status status = bsonExtractStringFieldWithDefault(source, shard.name(), "", &changeLogShard); if (!status.isOK()) return status; changeLog._shard = changeLogShard; } { std::string changeLogClientAddr; Status status = bsonExtractStringField(source, clientAddr.name(), &changeLogClientAddr); if (!status.isOK()) return status; changeLog._clientAddr = changeLogClientAddr; } { BSONElement changeLogTimeElem; Status status = bsonExtractTypedField(source, time.name(), Date, &changeLogTimeElem); if (!status.isOK()) return status; changeLog._time = changeLogTimeElem.date(); } { std::string changeLogWhat; Status status = bsonExtractStringField(source, what.name(), &changeLogWhat); if (!status.isOK()) return status; changeLog._what = changeLogWhat; } { std::string changeLogNs; Status status = bsonExtractStringFieldWithDefault(source, ns.name(), "", &changeLogNs); if (!status.isOK()) return status; changeLog._ns = changeLogNs; } { BSONElement changeLogDetailsElem; Status status = bsonExtractTypedField(source, details.name(), Object, &changeLogDetailsElem); if (!status.isOK()) return status; changeLog._details = changeLogDetailsElem.Obj().getOwned(); } return changeLog; }
Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc) { const BSONElement electionTimeElement = doc[kElectionTimeFieldName]; if (electionTimeElement.eoo()) { _electionTimeSet = false; } else if (electionTimeElement.type() == Timestamp) { _electionTimeSet = true; _electionTime = electionTimeElement._opTime(); } else if (electionTimeElement.type() == Date) { _electionTime = true; _electionTime = OpTime(electionTimeElement.date()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kElectionTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(electionTimeElement.type())); } const BSONElement timeElement = doc[kTimeFieldName]; if (timeElement.eoo()) { _timeSet = false; } else if (timeElement.isNumber()) { _timeSet = true; _time = Seconds(timeElement.numberLong()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kTimeFieldName << "\" field in reponse to replSetHeartbeat " "command to have a numeric type, but found type " << typeName(timeElement.type())); } const BSONElement opTimeElement = doc[kOpTimeFieldName]; if (opTimeElement.eoo()) { _opTimeSet = false; } else if (opTimeElement.type() == Timestamp) { _opTimeSet = true; _opTime = opTimeElement._opTime(); } else if (opTimeElement.type() == Date) { _opTimeSet = true; _opTime = OpTime(opTimeElement.date()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kOpTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(opTimeElement.type())); } const BSONElement electableElement = doc[kIsElectableFieldName]; if (electableElement.eoo()) { _electableSet = false; } else { _electableSet = true; _electable = electableElement.trueValue(); } _mismatch = doc[kMismatchFieldName].trueValue(); _isReplSet = doc[kIsReplSetFieldName].trueValue(); const BSONElement memberStateElement = doc[kMemberStateFieldName]; if (memberStateElement.eoo()) { _stateSet = false; } else if (memberStateElement.type() != NumberInt && memberStateElement.type() != NumberLong) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kMemberStateFieldName << "\" field in response to replSetHeartbeat " " command to have type NumberInt or NumberLong, but found type " << typeName(memberStateElement.type())); } else { long long stateInt = memberStateElement.numberLong(); if (stateInt < 0 || stateInt > MemberState::RS_MAX) { return Status(ErrorCodes::BadValue, str::stream() << "Value for \"" << kMemberStateFieldName << "\" in response to replSetHeartbeat is " " out of range; legal values are non-negative and no more than " << MemberState::RS_MAX); } _state = MemberState(static_cast<int>(stateInt)); } _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); const BSONElement versionElement = doc[kConfigVersionFieldName]; if (versionElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kConfigVersionFieldName << " field"); } if (versionElement.type() != NumberInt) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigVersionFieldName << "\" field in response to replSetHeartbeat to have " "type NumberInt, but found " << typeName(versionElement.type())); } _version = versionElement.numberInt(); const BSONElement replSetNameElement = doc[kReplSetFieldName]; if (replSetNameElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kReplSetFieldName << "\" field"); } if (replSetNameElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kReplSetFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(replSetNameElement.type())); } _setName = replSetNameElement.String(); const BSONElement hbMsgElement = doc[kHbMessageFieldName]; if (hbMsgElement.eoo()) { _hbmsg.clear(); } else if (hbMsgElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kHbMessageFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(hbMsgElement.type())); } _hbmsg = hbMsgElement.String(); const BSONElement syncingToElement = doc[kSyncSourceFieldName]; if (syncingToElement.eoo()) { _syncingTo.clear(); } else if (syncingToElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kSyncSourceFieldName << "\" field in response to replSetHeartbeat to " "have type String, but found " << typeName(syncingToElement.type())); } _syncingTo = syncingToElement.String(); const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); } else if (rsConfigElement.type() != Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigFieldName << "\" in response to replSetHeartbeat to have type " "Object, but found " << typeName(rsConfigElement.type())); } _configSet = true; return _config.initialize(rsConfigElement.Obj()); }
/* must be same type when called, unless both sides are #s */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; switch ( l.type() ) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: f = l.canonicalType() - r.canonicalType(); if ( f<0 ) return -1; return f==0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: case Date: if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; case NumberLong: if( r.type() == NumberLong ) { long long L = l._numberLong(); long long R = r._numberLong(); if( L < R ) return -1; if( L == R ) return 0; return 1; } // else fall through case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); bool lNan = !( left <= numeric_limits< double >::max() && left >= -numeric_limits< double >::max() ); bool rNan = !( right <= numeric_limits< double >::max() && right >= -numeric_limits< double >::max() ); if ( lNan ) { if ( rNan ) { return 0; } else { return -1; } } else if ( rNan ) { return 1; } x = left - right; if ( x < 0 ) return -1; return x == 0 ? 0 : 1; } case jstOID: return memcmp(l.value(), r.value(), 12); case Code: case Symbol: case String: /* todo: utf version */ return strcmp(l.valuestr(), r.valuestr()); case Object: case Array: return l.embeddedObject().woCompare( r.embeddedObject() ); case DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BinData: { int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value()+4, r.value()+4, lsz+1); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if ( c ) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case CodeWScope : { f = l.canonicalType() - r.canonicalType(); if ( f ) return f; f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); if ( f ) return f; f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ); if ( f ) return f; return 0; } default: out() << "compareElementValues: bad type " << (int) l.type() << endl; assert(false); } return -1; }
/* slave: pull some data from the master's oplog note: not yet in db mutex at this point. @return -1 error 0 ok, don't sleep 1 ok, sleep */ int ReplSource::sync_pullOpLog(int& nApplied) { int okResultCode = 1; string ns = string("local.oplog.$") + sourceName(); log(2) << "repl: sync_pullOpLog " << ns << " syncedTo:" << syncedTo.toStringLong() << '\n'; bool tailing = true; oplogReader.tailCheck(); bool initial = syncedTo.isNull(); if ( !oplogReader.haveCursor() || initial ) { if ( initial ) { // Important to grab last oplog timestamp before listing databases. syncToTailOfRemoteLog(); BSONObj info; bool ok = oplogReader.conn()->runCommand( "admin", BSON( "listDatabases" << 1 ), info ); massert( 10389 , "Unable to get database list", ok ); BSONObjIterator i( info.getField( "databases" ).embeddedObject() ); while( i.moreWithEOO() ) { BSONElement e = i.next(); if ( e.eoo() ) break; string name = e.embeddedObject().getField( "name" ).valuestr(); if ( !e.embeddedObject().getBoolField( "empty" ) ) { if ( name != "local" ) { if ( only.empty() || only == name ) { log( 2 ) << "adding to 'addDbNextPass': "******"$gte", syncedTo.asDate()); BSONObjBuilder query; query.append("ts", q.done()); if ( !only.empty() ) { // note we may here skip a LOT of data table scanning, a lot of work for the master. query.appendRegex("ns", string("^") + only); // maybe append "\\." here? } BSONObj queryObj = query.done(); // e.g. queryObj = { ts: { $gte: syncedTo } } oplogReader.tailingQuery(ns.c_str(), queryObj); tailing = false; } else { log(2) << "repl: tailing=true\n"; } if( !oplogReader.haveCursor() ) { problem() << "repl: dbclient::query returns null (conn closed?)" << endl; oplogReader.resetConnection(); return -1; } // show any deferred database creates from a previous pass { set<string>::iterator i = addDbNextPass.begin(); if ( i != addDbNextPass.end() ) { BSONObjBuilder b; b.append("ns", *i + '.'); b.append("op", "db"); BSONObj op = b.done(); sync_pullOpLog_applyOperation(op, false); } } if ( !oplogReader.more() ) { if ( tailing ) { log(2) << "repl: tailing & no new activity\n"; if( oplogReader.awaitCapable() ) okResultCode = 0; // don't sleep } else { log() << "repl: " << ns << " oplog is empty\n"; } { dblock lk; save(); } return okResultCode; } OpTime nextOpTime; { BSONObj op = oplogReader.next(); BSONElement ts = op.getField("ts"); if ( ts.type() != Date && ts.type() != Timestamp ) { string err = op.getStringField("$err"); if ( !err.empty() ) { // 13051 is "tailable cursor requested on non capped collection" if (op.getIntField("code") == 13051) { problem() << "trying to slave off of a non-master" << '\n'; massert( 13344 , "trying to slave off of a non-master", false ); } else { problem() << "repl: $err reading remote oplog: " + err << '\n'; massert( 10390 , "got $err reading remote oplog", false ); } } else { problem() << "repl: bad object read from remote oplog: " << op.toString() << '\n'; massert( 10391 , "repl: bad object read from remote oplog", false); } } nextOpTime = OpTime( ts.date() ); log(2) << "repl: first op time received: " << nextOpTime.toString() << '\n'; if ( initial ) { log(1) << "repl: initial run\n"; } if( tailing ) { if( !( syncedTo < nextOpTime ) ) { log() << "repl ASSERTION failed : syncedTo < nextOpTime" << endl; log() << "repl syncTo: " << syncedTo.toStringLong() << endl; log() << "repl nextOpTime: " << nextOpTime.toStringLong() << endl; assert(false); } oplogReader.putBack( op ); // op will be processed in the loop below nextOpTime = OpTime(); // will reread the op below } else if ( nextOpTime != syncedTo ) { // didn't get what we queried for - error Nullstream& l = log(); l << "repl: nextOpTime " << nextOpTime.toStringLong() << ' '; if ( nextOpTime < syncedTo ) l << "<??"; else l << ">"; l << " syncedTo " << syncedTo.toStringLong() << '\n'; log() << "repl: time diff: " << (nextOpTime.getSecs() - syncedTo.getSecs()) << "sec\n"; log() << "repl: tailing: " << tailing << '\n'; log() << "repl: data too stale, halting replication" << endl; replInfo = replAllDead = "data too stale halted replication"; assert( syncedTo < nextOpTime ); throw SyncException(); } else { /* t == syncedTo, so the first op was applied previously or it is the first op of initial query and need not be applied. */ } } // apply operations { int n = 0; time_t saveLast = time(0); while ( 1 ) { bool moreInitialSyncsPending = !addDbNextPass.empty() && n; // we need "&& n" to assure we actually process at least one op to get a sync point recorded in the first place. if ( moreInitialSyncsPending || !oplogReader.more() ) { dblock lk; // NOTE aaron 2011-03-29 This block may be unnecessary, but I'm leaving it in place to avoid changing timing behavior. { dbtemprelease t; if ( !moreInitialSyncsPending && oplogReader.more() ) { continue; } // otherwise, break out of loop so we can set to completed or clone more dbs } if( oplogReader.awaitCapable() && tailing ) okResultCode = 0; // don't sleep syncedTo = nextOpTime; save(); // note how far we are synced up to now log() << "repl: applied " << n << " operations" << endl; nApplied = n; log() << "repl: end sync_pullOpLog syncedTo: " << syncedTo.toStringLong() << endl; break; } else { } OCCASIONALLY if( n > 0 && ( n > 100000 || time(0) - saveLast > 60 ) ) { // periodically note our progress, in case we are doing a lot of work and crash dblock lk; syncedTo = nextOpTime; // can't update local log ts since there are pending operations from our peer save(); log() << "repl: checkpoint applied " << n << " operations" << endl; log() << "repl: syncedTo: " << syncedTo.toStringLong() << endl; saveLast = time(0); n = 0; } BSONObj op = oplogReader.next(); unsigned b = replApplyBatchSize; bool justOne = b == 1; scoped_ptr<writelock> lk( justOne ? 0 : new writelock() ); while( 1 ) { BSONElement ts = op.getField("ts"); if( !( ts.type() == Date || ts.type() == Timestamp ) ) { log() << "sync error: problem querying remote oplog record" << endl; log() << "op: " << op.toString() << endl; log() << "halting replication" << endl; replInfo = replAllDead = "sync error: no ts found querying remote oplog record"; throw SyncException(); } OpTime last = nextOpTime; nextOpTime = OpTime( ts.date() ); if ( !( last < nextOpTime ) ) { log() << "sync error: last applied optime at slave >= nextOpTime from master" << endl; log() << " last: " << last.toStringLong() << endl; log() << " nextOpTime: " << nextOpTime.toStringLong() << endl; log() << " halting replication" << endl; replInfo = replAllDead = "sync error last >= nextOpTime"; uassert( 10123 , "replication error last applied optime at slave >= nextOpTime from master", false); } if ( replSettings.slavedelay && ( unsigned( time( 0 ) ) < nextOpTime.getSecs() + replSettings.slavedelay ) ) { assert( justOne ); oplogReader.putBack( op ); _sleepAdviceTime = nextOpTime.getSecs() + replSettings.slavedelay + 1; dblock lk; if ( n > 0 ) { syncedTo = last; save(); } log() << "repl: applied " << n << " operations" << endl; log() << "repl: syncedTo: " << syncedTo.toStringLong() << endl; log() << "waiting until: " << _sleepAdviceTime << " to continue" << endl; return okResultCode; } sync_pullOpLog_applyOperation(op, !justOne); n++; if( --b == 0 ) break; // if to here, we are doing mulpile applications in a singel write lock acquisition if( !oplogReader.moreInCurrentBatch() ) { // break if no more in batch so we release lock while reading from the master break; } op = oplogReader.next(); getDur().commitIfNeeded(); } } } return okResultCode; }
Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc, long long term) { // Old versions set this even though they returned not "ok" _mismatch = doc[kMismatchFieldName].trueValue(); if (_mismatch) return Status(ErrorCodes::InconsistentReplicaSetNames, "replica set name doesn't match."); // Old versions sometimes set the replica set name ("set") but ok:0 const BSONElement replSetNameElement = doc[kReplSetFieldName]; if (replSetNameElement.eoo()) { _setName.clear(); } else if (replSetNameElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kReplSetFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(replSetNameElement.type())); } else { _setName = replSetNameElement.String(); } if (_setName.empty() && !doc[kOkFieldName].trueValue()) { std::string errMsg = doc[kErrMsgFieldName].str(); BSONElement errCodeElem = doc[kErrorCodeFieldName]; if (errCodeElem.ok()) { if (!errCodeElem.isNumber()) return Status(ErrorCodes::BadValue, "Error code is not a number!"); int errorCode = errCodeElem.numberInt(); return Status(ErrorCodes::Error(errorCode), errMsg); } return Status(ErrorCodes::UnknownError, errMsg); } const BSONElement hasDataElement = doc[kHasDataFieldName]; _hasDataSet = !hasDataElement.eoo(); _hasData = hasDataElement.trueValue(); const BSONElement electionTimeElement = doc[kElectionTimeFieldName]; if (electionTimeElement.eoo()) { _electionTimeSet = false; } else if (electionTimeElement.type() == bsonTimestamp) { _electionTimeSet = true; _electionTime = electionTimeElement.timestamp(); } else if (electionTimeElement.type() == Date) { _electionTimeSet = true; _electionTime = Timestamp(electionTimeElement.date()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kElectionTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(electionTimeElement.type())); } const BSONElement timeElement = doc[kTimeFieldName]; if (timeElement.eoo()) { _timeSet = false; } else if (timeElement.isNumber()) { _timeSet = true; _time = Seconds(timeElement.numberLong()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kTimeFieldName << "\" field in response to replSetHeartbeat " "command to have a numeric type, but found type " << typeName(timeElement.type())); } _isReplSet = doc[kIsReplSetFieldName].trueValue(); Status termStatus = bsonExtractIntegerField(doc, kTermFieldName, &_term); if (!termStatus.isOK() && termStatus != ErrorCodes::NoSuchKey) { return termStatus; } // In order to support both the 3.0(V0) and 3.2(V1) heartbeats we must parse the OpTime // field based on its type. If it is a Date, we parse it as the timestamp and use // initialize's term argument to complete the OpTime type. If it is an Object, then it's // V1 and we construct an OpTime out of its nested fields. const BSONElement opTimeElement = doc[kOpTimeFieldName]; if (opTimeElement.eoo()) { _opTimeSet = false; } else if (opTimeElement.type() == bsonTimestamp) { _opTimeSet = true; _opTime = OpTime(opTimeElement.timestamp(), term); } else if (opTimeElement.type() == Date) { _opTimeSet = true; _opTime = OpTime(Timestamp(opTimeElement.date()), term); } else if (opTimeElement.type() == Object) { Status status = bsonExtractOpTimeField(doc, kOpTimeFieldName, &_opTime); _opTimeSet = true; // since a v1 OpTime was in the response, the member must be part of a replset _isReplSet = true; } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kOpTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(opTimeElement.type())); } const BSONElement electableElement = doc[kIsElectableFieldName]; if (electableElement.eoo()) { _electableSet = false; } else { _electableSet = true; _electable = electableElement.trueValue(); } const BSONElement memberStateElement = doc[kMemberStateFieldName]; if (memberStateElement.eoo()) { _stateSet = false; } else if (memberStateElement.type() != NumberInt && memberStateElement.type() != NumberLong) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kMemberStateFieldName << "\" field in response to replSetHeartbeat " "command to have type NumberInt or NumberLong, but found type " << typeName(memberStateElement.type())); } else { long long stateInt = memberStateElement.numberLong(); if (stateInt < 0 || stateInt > MemberState::RS_MAX) { return Status(ErrorCodes::BadValue, str::stream() << "Value for \"" << kMemberStateFieldName << "\" in response to replSetHeartbeat is " "out of range; legal values are non-negative and no more than " << MemberState::RS_MAX); } _stateSet = true; _state = MemberState(static_cast<int>(stateInt)); } _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); // Not required for the case of uninitialized members -- they have no config const BSONElement configVersionElement = doc[kConfigVersionFieldName]; // If we have an optime then we must have a configVersion if (_opTimeSet && configVersionElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kConfigVersionFieldName << "\" field even though initialized"); } // If there is a "v" (config version) then it must be an int. if (!configVersionElement.eoo() && configVersionElement.type() != NumberInt) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigVersionFieldName << "\" field in response to replSetHeartbeat to have " "type NumberInt, but found " << typeName(configVersionElement.type())); } _configVersion = configVersionElement.numberInt(); const BSONElement hbMsgElement = doc[kHbMessageFieldName]; if (hbMsgElement.eoo()) { _hbmsg.clear(); } else if (hbMsgElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kHbMessageFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(hbMsgElement.type())); } else { _hbmsg = hbMsgElement.String(); } const BSONElement syncingToElement = doc[kSyncSourceFieldName]; if (syncingToElement.eoo()) { _syncingTo = HostAndPort(); } else if (syncingToElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kSyncSourceFieldName << "\" field in response to replSetHeartbeat to " "have type String, but found " << typeName(syncingToElement.type())); } else { _syncingTo = HostAndPort(syncingToElement.String()); } const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); return Status::OK(); } else if (rsConfigElement.type() != Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigFieldName << "\" in response to replSetHeartbeat to have type " "Object, but found " << typeName(rsConfigElement.type())); } _configSet = true; return _config.initialize(rsConfigElement.Obj()); }
// fromBSON to Key format KeyV1Owned::KeyV1Owned(const BSONObj& obj) { BSONObj::iterator i(obj); unsigned char bits = 0; while( 1 ) { BSONElement e = i.next(); if( i.more() ) bits |= cHASMORE; switch( e.type() ) { case MinKey: b.appendUChar(cminkey|bits); break; case jstNULL: b.appendUChar(cnull|bits); break; case MaxKey: b.appendUChar(cmaxkey|bits); break; case Bool: b.appendUChar( (e.boolean()?ctrue:cfalse) | bits ); break; case jstOID: b.appendUChar(coid|bits); b.appendBuf(&e.__oid(), sizeof(OID)); break; case BinData: { int t = e.binDataType(); // 0-7 and 0x80 to 0x87 are supported by Key if( (t & 0x78) == 0 && t != ByteArrayDeprecated ) { int len; const char * d = e.binData(len); if( len <= BinDataLenMax ) { int code = BinDataLengthToCode[len]; if( code >= 0 ) { if( t >= 128 ) t = (t-128) | 0x08; dassert( (code&t) == 0 ); b.appendUChar( cbindata|bits ); b.appendUChar( code | t ); b.appendBuf(d, len); break; } } } traditional(obj); return; } case Date: b.appendUChar(cdate|bits); b.appendStruct(e.date()); break; case String: { b.appendUChar(cstring|bits); // note we do not store the terminating null, to save space. unsigned x = (unsigned) e.valuestrsize() - 1; if( x > 255 ) { traditional(obj); return; } b.appendUChar(x); b.appendBuf(e.valuestr(), x); break; } case NumberInt: b.appendUChar(cint|bits); b.appendNum((double) e._numberInt()); break; case NumberLong: { long long n = e._numberLong(); long long m = 2LL << 52; DEV { long long d = m-1; verify( ((long long) ((double) -d)) == -d ); } if( n >= m || n <= -m ) { // can't represent exactly as a double traditional(obj); return; } b.appendUChar(clong|bits); b.appendNum((double) n); break; } case NumberDouble: { double d = e._numberDouble(); if( isNaN(d) ) { traditional(obj); return; } b.appendUChar(cdouble|bits); b.appendNum(d); break; } default: // if other types involved, store as traditional BSON traditional(obj); return; } if( !i.more() ) break; bits = 0; } _keyData = (const unsigned char *) b.buf(); dassert( b.len() == dataSize() ); // check datasize method is correct dassert( (*_keyData & cNOTUSED) == 0 ); }
Status ReplSetHeartbeatResponse::initialize(const BSONObj& doc) { // Old versions set this even though they returned not "ok" _mismatch = doc[kMismatchFieldName].trueValue(); if (_mismatch) return Status(ErrorCodes::InconsistentReplicaSetNames, "replica set name doesn't match."); // Old versions sometimes set the replica set name ("set") but ok:0 const BSONElement replSetNameElement = doc[kReplSetFieldName]; if (replSetNameElement.eoo()) { _setName.clear(); } else if (replSetNameElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kReplSetFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(replSetNameElement.type())); } else { _setName = replSetNameElement.String(); } if (_setName.empty() && !doc[kOkFieldName].trueValue()) { std::string errMsg = doc[kErrMsgFieldName].str(); BSONElement errCodeElem = doc[kErrorCodeFieldName]; if (errCodeElem.ok()) { if (!errCodeElem.isNumber()) return Status(ErrorCodes::BadValue, "Error code is not a number!"); int errorCode = errCodeElem.numberInt(); return Status(ErrorCodes::Error(errorCode), errMsg); } return Status(ErrorCodes::UnknownError, errMsg); } const BSONElement hasDataElement = doc[kHasDataFieldName]; _hasDataSet = !hasDataElement.eoo(); _hasData = hasDataElement.trueValue(); const BSONElement electionTimeElement = doc[kElectionTimeFieldName]; if (electionTimeElement.eoo()) { _electionTimeSet = false; } else if (electionTimeElement.type() == Timestamp) { _electionTimeSet = true; _electionTime = electionTimeElement._opTime(); } else if (electionTimeElement.type() == Date) { _electionTimeSet = true; _electionTime = OpTime(electionTimeElement.date()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kElectionTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(electionTimeElement.type())); } const BSONElement timeElement = doc[kTimeFieldName]; if (timeElement.eoo()) { _timeSet = false; } else if (timeElement.isNumber()) { _timeSet = true; _time = Seconds(timeElement.numberLong()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kTimeFieldName << "\" field in response to replSetHeartbeat " "command to have a numeric type, but found type " << typeName(timeElement.type())); } const BSONElement opTimeElement = doc[kOpTimeFieldName]; if (opTimeElement.eoo()) { _opTimeSet = false; } else if (opTimeElement.type() == Timestamp) { _opTimeSet = true; _opTime = opTimeElement._opTime(); } else if (opTimeElement.type() == Date) { _opTimeSet = true; _opTime = OpTime(opTimeElement.date()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kOpTimeFieldName << "\" field in response to replSetHeartbeat " "command to have type Date or Timestamp, but found type " << typeName(opTimeElement.type())); } const BSONElement electableElement = doc[kIsElectableFieldName]; if (electableElement.eoo()) { _electableSet = false; } else { _electableSet = true; _electable = electableElement.trueValue(); } _isReplSet = doc[kIsReplSetFieldName].trueValue(); const BSONElement memberStateElement = doc[kMemberStateFieldName]; if (memberStateElement.eoo()) { _stateSet = false; } else if (memberStateElement.type() != NumberInt && memberStateElement.type() != NumberLong) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kMemberStateFieldName << "\" field in response to replSetHeartbeat " "command to have type NumberInt or NumberLong, but found type " << typeName(memberStateElement.type())); } else { long long stateInt = memberStateElement.numberLong(); if (stateInt < 0 || stateInt > MemberState::RS_MAX) { return Status(ErrorCodes::BadValue, str::stream() << "Value for \"" << kMemberStateFieldName << "\" in response to replSetHeartbeat is " "out of range; legal values are non-negative and no more than " << MemberState::RS_MAX); } _stateSet = true; _state = MemberState(static_cast<int>(stateInt)); } _stateDisagreement = doc[kHasStateDisagreementFieldName].trueValue(); // Not required for the case of uninitialized members -- they have no config const BSONElement versionElement = doc[kConfigVersionFieldName]; // If we have an optime then we must have a version if (_opTimeSet && versionElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << "Response to replSetHeartbeat missing required \"" << kConfigVersionFieldName << "\" field even though initialized"); } // If there is a "v" (config version) then it must be an int. if (!versionElement.eoo() && versionElement.type() != NumberInt) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigVersionFieldName << "\" field in response to replSetHeartbeat to have " "type NumberInt, but found " << typeName(versionElement.type())); } _version = versionElement.numberInt(); const BSONElement hbMsgElement = doc[kHbMessageFieldName]; if (hbMsgElement.eoo()) { _hbmsg.clear(); } else if (hbMsgElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kHbMessageFieldName << "\" field in response to replSetHeartbeat to have " "type String, but found " << typeName(hbMsgElement.type())); } else { _hbmsg = hbMsgElement.String(); } const BSONElement syncingToElement = doc[kSyncSourceFieldName]; if (syncingToElement.eoo()) { _syncingTo.clear(); } else if (syncingToElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kSyncSourceFieldName << "\" field in response to replSetHeartbeat to " "have type String, but found " << typeName(syncingToElement.type())); } else { _syncingTo = syncingToElement.String(); } const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); return Status::OK(); } else if (rsConfigElement.type() != Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigFieldName << "\" in response to replSetHeartbeat to have type " "Object, but found " << typeName(rsConfigElement.type())); } _configSet = true; return _config.initialize(rsConfigElement.Obj()); }
int run() { if (!hasParam("from")) { log() << "need to specify --from" << endl; return -1; } _oplogns = getParam("oplogns"); Client::initThread( "mongo2toku" ); LOG(1) << "going to connect" << endl; _rconn.reset(ScopedDbConnection::getScopedDbConnection(getParam("from"))); LOG(1) << "connected" << endl; { string tsString; if (hasParam("ts")) { tsString = getParam("ts"); } else { try { ifstream tsFile; tsFile.exceptions(std::ifstream::badbit | std::ifstream::failbit); tsFile.open(_tsFilename); tsFile >> tsString; tsFile.close(); } catch (std::exception &e) { warning() << "Couldn't read OpTime from file " << _tsFilename << ": " << e.what() << endl; } } if (tsString.empty()) { warning() << "No starting OpTime provided. " << "Please find the right starting point and run again with --ts." << endl; return -1; } unsigned secs, i; OpTime maxOpTimeSynced; int r = sscanf(tsString.c_str(), "%u:%u", &secs, &i); if (r != 2) { warning() << "need to specify --ts as <secs>:<inc>" << endl; return -1; } maxOpTimeSynced = OpTime(secs, i); _player.reset(new VanillaOplogPlayer(conn(), _host, maxOpTimeSynced, running, _logAtExit)); } const int reportingPeriod = getParam("reportingPeriod", 10); try { while (running) { const int tailingQueryOptions = QueryOption_SlaveOk | QueryOption_CursorTailable | QueryOption_OplogReplay | QueryOption_AwaitData; BSONObjBuilder queryBuilder; BSONObjBuilder gteBuilder(queryBuilder.subobjStart("ts")); gteBuilder.appendTimestamp("$gte", _player->maxOpTimeSynced().asDate()); gteBuilder.doneFast(); BSONObj query = queryBuilder.done(); BSONObj res; auto_ptr<DBClientCursor> cursor(_rconn->conn().query(_oplogns, query, 0, 0, &res, tailingQueryOptions)); if (!cursor->more()) { log() << "oplog query returned no results, sleeping 10 seconds..." << endl; sleepsecs(10); log() << "retrying" << endl; continue; } BSONObj firstObj = cursor->next(); { BSONElement tsElt = firstObj["ts"]; if (!tsElt.ok()) { log() << "oplog format error: " << firstObj << " missing 'ts' field." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } OpTime firstTime(tsElt.date()); if (firstTime != _player->maxOpTimeSynced()) { warning() << "Tried to start at OpTime " << _player->maxOpTimeSyncedStr() << ", but didn't find anything before " << fmtOpTime(firstTime) << "!" << endl; warning() << "This may mean your oplog has been truncated past the point you are trying to resume from." << endl; warning() << "Either retry with a different value of --ts, or restart your migration procedure." << endl; _rconn->done(); _rconn.reset(); return -1; } } report(); while (running && cursor->more()) { while (running && cursor->moreInCurrentBatch()) { BSONObj obj = cursor->next(); LOG(2) << obj << endl; bool ok = _player->processObj(obj); if (!ok) { logPosition(); _rconn->done(); _rconn.reset(); return -1; } } _player->flushInserts(); if (_reportingTimer.seconds() >= reportingPeriod) { report(); } } } } catch (DBException &e) { warning() << "Caught exception " << e.what() << " while processing. Exiting..." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } catch (...) { warning() << "Caught unknown exception while processing. Exiting..." << endl; logPosition(); _rconn->done(); _rconn.reset(); return -1; } if (_logAtExit) { logPosition(); _rconn->done(); _rconn.reset(); return 0; } else { _rconn->done(); _rconn.reset(); return -1; } }
void lua_push_value(lua_State *L, const BSONElement &elem) { int type = elem.type(); switch(type) { case mongo::Undefined: lua_pushnil(L); break; case mongo::NumberInt: lua_pushinteger(L, elem.numberInt()); break; case mongo::NumberLong: case mongo::NumberDouble: lua_pushnumber(L, elem.number()); break; case mongo::Bool: lua_pushboolean(L, elem.boolean()); break; case mongo::String: lua_pushstring(L, elem.valuestr()); break; case mongo::Array: bson_to_array(L, elem.embeddedObject()); break; case mongo::Object: bson_to_table(L, elem.embeddedObject()); break; case mongo::Date: push_bsontype_table(L, mongo::Date); lua_pushnumber(L, elem.date()); lua_rawseti(L, -2, 1); break; case mongo::Timestamp: push_bsontype_table(L, mongo::Date); lua_pushnumber(L, elem.timestampTime()); lua_rawseti(L, -2, 1); break; case mongo::Symbol: push_bsontype_table(L, mongo::Symbol); lua_pushstring(L, elem.valuestr()); lua_rawseti(L, -2, 1); break; case mongo::RegEx: push_bsontype_table(L, mongo::RegEx); lua_pushstring(L, elem.regex()); lua_rawseti(L, -2, 1); lua_pushstring(L, elem.regexFlags()); lua_rawseti(L, -2, 2); break; case mongo::jstOID: push_bsontype_table(L, mongo::jstOID); lua_pushstring(L, elem.__oid().str().c_str()); lua_rawseti(L, -2, 1); break; case mongo::jstNULL: push_bsontype_table(L, mongo::jstNULL); break; case mongo::EOO: break; default: luaL_error(L, LUAMONGO_UNSUPPORTED_BSON_TYPE, bson_name(type)); } }