Compare commits
88 Commits
CLOUDP-698
...
r1.6.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aef371ecf5 | ||
|
|
5b66c47327 | ||
|
|
0260ce050b | ||
|
|
3c1fa57776 | ||
|
|
19a0f996fa | ||
|
|
0fda3ce40f | ||
|
|
4a9135c3b6 | ||
|
|
0af2db40cf | ||
|
|
f93b0d654f | ||
|
|
9ff3ddc944 | ||
|
|
cd47c92322 | ||
|
|
2b869d6dfa | ||
|
|
c9feeb823d | ||
|
|
38da020af0 | ||
|
|
79b5c8023b | ||
|
|
baa4cb9c04 | ||
|
|
66befc517c | ||
|
|
e070747d94 | ||
|
|
921dbd018b | ||
|
|
964b3436ef | ||
|
|
0840daf31a | ||
|
|
a3dd77e7ec | ||
|
|
4a65b51c57 | ||
|
|
bdfefa42c5 | ||
|
|
625b4c4378 | ||
|
|
4099bc52cc | ||
|
|
5c6f0dcfbd | ||
|
|
b620e3327e | ||
|
|
92d5eb42af | ||
|
|
aaae92dedb | ||
|
|
0e78196fd5 | ||
|
|
6122c120c3 | ||
|
|
7b02bf761d | ||
|
|
00e9040236 | ||
|
|
f0d0aad23d | ||
|
|
f6aad0935e | ||
|
|
7093e6e585 | ||
|
|
c5f5f9a4f3 | ||
|
|
19b587d925 | ||
|
|
31d81b823d | ||
|
|
e280c561f1 | ||
|
|
1a30dad111 | ||
|
|
3770916e05 | ||
|
|
67159d2583 | ||
|
|
81da9cda7f | ||
|
|
415c264123 | ||
|
|
4454a8a0a0 | ||
|
|
d1c3edcf33 | ||
|
|
1948efc6a4 | ||
|
|
c3855123b5 | ||
|
|
2976396903 | ||
|
|
aa5d314ae9 | ||
|
|
d3b427b96f | ||
|
|
3de268fcae | ||
|
|
54239a3676 | ||
|
|
1d7dfe2868 | ||
|
|
f1f53ef3c1 | ||
|
|
356eeb5a62 | ||
|
|
2800a96e56 | ||
|
|
0c8f696e79 | ||
|
|
b58d62a194 | ||
|
|
2ba8ac25f1 | ||
|
|
edb14c522b | ||
|
|
af35eebfb6 | ||
|
|
edffe867a5 | ||
|
|
0e8ef6bca0 | ||
|
|
b59584f3dd | ||
|
|
3cc86177ce | ||
|
|
dcfab78c4b | ||
|
|
ba166df412 | ||
|
|
2c7f164b65 | ||
|
|
53d1c8bbad | ||
|
|
e4fcc800f7 | ||
|
|
7abf0580ca | ||
|
|
ae1e0804da | ||
|
|
50b7bbe934 | ||
|
|
fd26b536e9 | ||
|
|
6f6aa20e92 | ||
|
|
55937a8f3e | ||
|
|
8947d06986 | ||
|
|
8c095b2cb2 | ||
|
|
2e6aeb0229 | ||
|
|
cb661f73fd | ||
|
|
63f894763d | ||
|
|
2c3d88336e | ||
|
|
c542dbd78a | ||
|
|
b5ce278c18 | ||
|
|
a432ac592e |
@@ -387,16 +387,7 @@ namespace mongo {
|
||||
}
|
||||
break;
|
||||
case NumberDouble:
|
||||
{
|
||||
stringstream tmp;
|
||||
tmp.precision( 16 );
|
||||
tmp << number();
|
||||
string n = tmp.str();
|
||||
s << n;
|
||||
// indicate this is a double:
|
||||
if( strchr(n.c_str(), '.') == 0 && strchr(n.c_str(), 'E') == 0 && strchr(n.c_str(), 'N') == 0 )
|
||||
s << ".0";
|
||||
}
|
||||
s.appendDoubleNice( number() );
|
||||
break;
|
||||
case NumberLong:
|
||||
s << _numberLong();
|
||||
|
||||
@@ -164,6 +164,7 @@ namespace mongo {
|
||||
#define SBNUM(val,maxSize,macro) \
|
||||
int prev = _buf.l; \
|
||||
int z = sprintf( _buf.grow(maxSize) , macro , (val) ); \
|
||||
assert( z >= 0 ); \
|
||||
_buf.l = prev + z; \
|
||||
return *this;
|
||||
|
||||
@@ -197,6 +198,17 @@ namespace mongo {
|
||||
}
|
||||
#undef SBNUM
|
||||
|
||||
void appendDoubleNice( double x ){
|
||||
int prev = _buf.l;
|
||||
char * start = _buf.grow( 32 );
|
||||
int z = sprintf( start , "%.16g" , x );
|
||||
assert( z >= 0 );
|
||||
_buf.l = prev + z;
|
||||
if( strchr(start, '.') == 0 && strchr(start, 'E') == 0 && strchr(start, 'N') == 0 ){
|
||||
write( ".0" , 2 );
|
||||
}
|
||||
}
|
||||
|
||||
void write( const char* buf, int len){
|
||||
memcpy( _buf.grow( len ) , buf , len );
|
||||
}
|
||||
|
||||
@@ -1063,6 +1063,18 @@ namespace mongo {
|
||||
return checkMaster()->findOne(a,b,c,d);
|
||||
}
|
||||
|
||||
bool DBClientReplicaSet::isMember( const DBConnector * conn ) const {
|
||||
if ( conn == this )
|
||||
return true;
|
||||
|
||||
for ( unsigned i=0; i<_conns.size(); i++ )
|
||||
if ( _conns[i]->isMember( conn ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool serverAlive( const string &uri ) {
|
||||
DBClientConnection c( false, 0, 20 ); // potentially the connection to server could fail while we're checking if it's alive - so use timeouts
|
||||
string err;
|
||||
|
||||
@@ -106,10 +106,11 @@ namespace mongo {
|
||||
_finishInit();
|
||||
}
|
||||
|
||||
ConnectionString( ConnectionType type , const vector<HostAndPort>& servers )
|
||||
: _type( type ) , _servers( servers ){
|
||||
_finishInit();
|
||||
}
|
||||
// TODO Delete if nobody is using
|
||||
//ConnectionString( ConnectionType type , const vector<HostAndPort>& servers )
|
||||
// : _type( type ) , _servers( servers ){
|
||||
// _finishInit();
|
||||
//}
|
||||
|
||||
ConnectionString( ConnectionType type , const string& s , const string& setName = "" ){
|
||||
_type = type;
|
||||
@@ -156,6 +157,14 @@ namespace mongo {
|
||||
|
||||
static ConnectionString parse( const string& url , string& errmsg );
|
||||
|
||||
string getSetName() const{
|
||||
return _setName;
|
||||
}
|
||||
|
||||
vector<HostAndPort> getServers() const {
|
||||
return _servers;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ConnectionString(){
|
||||
@@ -314,7 +323,7 @@ namespace mongo {
|
||||
/** Typically one uses the QUERY(...) macro to construct a Query object.
|
||||
Example: QUERY( "age" << 33 << "school" << "UCLA" )
|
||||
*/
|
||||
#define QUERY(x) Query( BSON(x) )
|
||||
#define QUERY(x) mongo::Query( BSON(x) )
|
||||
|
||||
/**
|
||||
interface that handles communication with the db
|
||||
@@ -329,6 +338,8 @@ namespace mongo {
|
||||
|
||||
/* used by QueryOption_Exhaust. To use that your subclass must implement this. */
|
||||
virtual void recv( Message& m ) { assert(false); }
|
||||
|
||||
virtual string getServerAddress() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -739,8 +750,6 @@ namespace mongo {
|
||||
*/
|
||||
virtual void update( const string &ns , Query query , BSONObj obj , bool upsert = false , bool multi = false );
|
||||
|
||||
virtual string getServerAddress() const = 0;
|
||||
|
||||
virtual bool isFailed() const = 0;
|
||||
|
||||
virtual void killCursor( long long cursorID ) = 0;
|
||||
@@ -758,6 +767,9 @@ namespace mongo {
|
||||
virtual void say( Message& toSend ) = 0;
|
||||
|
||||
virtual ConnectionString::ConnectionType type() const = 0;
|
||||
|
||||
/** @return true if conn is either equal to or contained in this connection */
|
||||
virtual bool isMember( const DBConnector * conn ) const = 0;
|
||||
}; // DBClientBase
|
||||
|
||||
class DBClientReplicaSet;
|
||||
@@ -892,11 +904,16 @@ namespace mongo {
|
||||
virtual bool call( Message &toSend, Message &response, bool assertOk = true );
|
||||
|
||||
virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
|
||||
|
||||
virtual bool isMember( const DBConnector * conn ) const { return this == conn; };
|
||||
|
||||
virtual void checkResponse( const char *data, int nReturned );
|
||||
|
||||
protected:
|
||||
friend class SyncClusterConnection;
|
||||
virtual void recv( Message& m );
|
||||
virtual void sayPiggyBack( Message &toSend );
|
||||
virtual void checkResponse( const char *data, int nReturned );
|
||||
|
||||
};
|
||||
|
||||
/** Use this class to connect to a replica set of servers. The class will manage
|
||||
@@ -987,9 +1004,12 @@ namespace mongo {
|
||||
|
||||
virtual ConnectionString::ConnectionType type() const { return ConnectionString::SET; }
|
||||
|
||||
virtual bool isMember( const DBConnector * conn ) const;
|
||||
|
||||
virtual void checkResponse( const char *data, int nReturned ) { checkMaster()->checkResponse( data , nReturned ); }
|
||||
|
||||
protected:
|
||||
virtual void sayPiggyBack( Message &toSend ) { assert(false); }
|
||||
virtual void checkResponse( const char *data, int nReturned ) { assert(false); }
|
||||
virtual void sayPiggyBack( Message &toSend ) { checkMaster()->say( toSend ); }
|
||||
|
||||
bool isFailed() const {
|
||||
return _currentMaster == 0 || _currentMaster->isFailed();
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace mongo {
|
||||
|
||||
void DBClientCursor::attach( AScopedConnection * conn ){
|
||||
assert( _scopedHost.size() == 0 );
|
||||
assert( connector == conn->get() );
|
||||
assert( conn->get()->isMember( connector ) );
|
||||
_scopedHost = conn->getHost();
|
||||
conn->done();
|
||||
connector = 0;
|
||||
|
||||
@@ -109,9 +109,6 @@ namespace mongo {
|
||||
|
||||
|
||||
bool DistributedLock::lock_try( string why , BSONObj * other ){
|
||||
// check for recrusive
|
||||
assert( getState() == 0 );
|
||||
|
||||
ScopedDbConnection conn( _conn );
|
||||
|
||||
BSONObjBuilder queryBuilder;
|
||||
@@ -136,7 +133,7 @@ namespace mongo {
|
||||
return false;
|
||||
}
|
||||
|
||||
Date_t elapsed = jsTime() - lastPing["ping"].Date(); // in ms
|
||||
unsigned long long elapsed = jsTime() - lastPing["ping"].Date(); // in ms
|
||||
elapsed = elapsed / ( 1000 * 60 ); // convert to minutes
|
||||
|
||||
if ( elapsed <= _takeoverMinutes ){
|
||||
@@ -208,18 +205,33 @@ namespace mongo {
|
||||
if ( ! gotLock )
|
||||
return false;
|
||||
|
||||
_state.set( 1 );
|
||||
return true;
|
||||
}
|
||||
|
||||
void DistributedLock::unlock(){
|
||||
ScopedDbConnection conn( _conn );
|
||||
conn->update( _ns , _id, BSON( "$set" << BSON( "state" << 0 ) ) );
|
||||
log(1) << "dist_lock unlock: " << conn->findOne( _ns , _id ) << endl;
|
||||
conn.done();
|
||||
const int maxAttempts = 3;
|
||||
int attempted = 0;
|
||||
while ( ++attempted <= maxAttempts ) {
|
||||
|
||||
try {
|
||||
ScopedDbConnection conn( _conn );
|
||||
conn->update( _ns , _id, BSON( "$set" << BSON( "state" << 0 ) ) );
|
||||
log(1) << "dist_lock unlock: " << conn->findOne( _ns , _id ) << endl;
|
||||
conn.done();
|
||||
|
||||
return;
|
||||
|
||||
|
||||
_state.set( 0 );
|
||||
} catch ( std::exception& e) {
|
||||
log( LL_WARNING ) << "dist_lock " << _name << " failed to contact config server in unlock attempt "
|
||||
<< attempted << ": " << e.what() << endl;
|
||||
|
||||
sleepsecs(1 << attempted);
|
||||
}
|
||||
}
|
||||
|
||||
log( LL_WARNING ) << "dist_lock couldn't consumate unlock request. " << "Lock " << _name
|
||||
<< " will be taken over after " << _takeoverMinutes << " minutes timeout" << endl;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -36,14 +36,6 @@ namespace mongo {
|
||||
*/
|
||||
DistributedLock( const ConnectionString& conn , const string& name , unsigned takeoverMinutes = 10 );
|
||||
|
||||
int getState(){
|
||||
return _state.get();
|
||||
}
|
||||
|
||||
bool isLocked(){
|
||||
return _state.get() != 0;
|
||||
}
|
||||
|
||||
bool lock_try( string why , BSONObj * other = 0 );
|
||||
void unlock();
|
||||
|
||||
@@ -54,8 +46,6 @@ namespace mongo {
|
||||
|
||||
string _ns;
|
||||
BSONObj _id;
|
||||
|
||||
ThreadLocalValue<int> _state;
|
||||
};
|
||||
|
||||
class dist_lock_try {
|
||||
|
||||
@@ -66,7 +66,6 @@ namespace mongo {
|
||||
}
|
||||
|
||||
BSONObj GridFS::storeFile( const char* data , size_t length , const string& remoteName , const string& contentType){
|
||||
massert( 10279 , "large files not yet implemented", length <= 0xffffffff);
|
||||
char const * const end = data + length;
|
||||
|
||||
OID id;
|
||||
@@ -127,8 +126,6 @@ namespace mongo {
|
||||
if (fd != stdin)
|
||||
fclose( fd );
|
||||
|
||||
massert( 10280 , "large files not yet implemented", length <= 0xffffffff);
|
||||
|
||||
return insertFile((remoteName.empty() ? fileName : remoteName), id, length, contentType);
|
||||
}
|
||||
|
||||
|
||||
@@ -328,6 +328,38 @@ namespace mongo {
|
||||
void ParallelSortClusteredCursor::_finishCons(){
|
||||
_numServers = _servers.size();
|
||||
_cursors = 0;
|
||||
|
||||
if ( ! _sortKey.isEmpty() && ! _fields.isEmpty() ){
|
||||
// we need to make sure the sort key is in the project
|
||||
bool isNegative = false;
|
||||
BSONObjBuilder b;
|
||||
{
|
||||
BSONObjIterator i( _fields );
|
||||
while ( i.more() ){
|
||||
BSONElement e = i.next();
|
||||
b.append( e );
|
||||
if ( ! e.trueValue() )
|
||||
isNegative = true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
BSONObjIterator i( _sortKey );
|
||||
while ( i.more() ){
|
||||
BSONElement e = i.next();
|
||||
BSONElement f = _fields.getField( e.fieldName() );
|
||||
if ( isNegative ){
|
||||
uassert( 13431 , "have to have sort key in projection and removing it" , f.eoo() );
|
||||
}
|
||||
else if ( f.eoo() ){
|
||||
// add to projection
|
||||
b.append( e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_fields = b.obj();
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelSortClusteredCursor::_init(){
|
||||
|
||||
@@ -369,4 +369,16 @@ namespace mongo {
|
||||
// should never need to do this
|
||||
assert(0);
|
||||
}
|
||||
|
||||
bool SyncClusterConnection::isMember( const DBConnector * conn ) const {
|
||||
if ( conn == this )
|
||||
return true;
|
||||
|
||||
for ( unsigned i=0; i<_conns.size(); i++ )
|
||||
if ( _conns[i]->isMember( conn ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -90,6 +90,8 @@ namespace mongo {
|
||||
|
||||
virtual ConnectionString::ConnectionType type() const { return ConnectionString::SYNC; }
|
||||
|
||||
virtual bool isMember( const DBConnector * conn ) const;
|
||||
|
||||
private:
|
||||
SyncClusterConnection( SyncClusterConnection& prev );
|
||||
string _toString() const;
|
||||
|
||||
@@ -259,6 +259,29 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
|
||||
BSONObj CurOp::query( bool threadSafe ) {
|
||||
if( querySize() == 1 ) {
|
||||
return _tooBig;
|
||||
}
|
||||
|
||||
if ( ! threadSafe ){
|
||||
BSONObj o(_queryBuf);
|
||||
return o;
|
||||
}
|
||||
|
||||
int size = querySize();
|
||||
int before = checksum( _queryBuf , size );
|
||||
BSONObj a(_queryBuf);
|
||||
BSONObj b = a.copy();
|
||||
int after = checksum( _queryBuf , size );
|
||||
|
||||
if ( before == after )
|
||||
return b;
|
||||
|
||||
return BSON( "msg" << "query changed while capturing" );
|
||||
}
|
||||
|
||||
|
||||
BSONObj CurOp::infoNoauth( int attempt ) {
|
||||
BSONObjBuilder b;
|
||||
b.append("opid", _opNum);
|
||||
@@ -402,7 +425,7 @@ namespace mongo {
|
||||
tablecell( ss , co.getOp() );
|
||||
tablecell( ss , co.getNS() );
|
||||
if ( co.haveQuery() )
|
||||
tablecell( ss , co.query() );
|
||||
tablecell( ss , co.query( true ) );
|
||||
else
|
||||
tablecell( ss , "" );
|
||||
tablecell( ss , co.getRemoteString() );
|
||||
|
||||
@@ -32,27 +32,37 @@
|
||||
|
||||
namespace mongo {
|
||||
|
||||
CCById ClientCursor::clientCursorsById;
|
||||
CCByLoc ClientCursor::byLoc;
|
||||
boost::recursive_mutex ClientCursor::ccmutex;
|
||||
typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
|
||||
|
||||
unsigned ClientCursor::byLocSize() {
|
||||
CCById ClientCursor::clientCursorsById;
|
||||
boost::recursive_mutex ClientCursor::ccmutex;
|
||||
long long ClientCursor::numberTimedOut = 0;
|
||||
|
||||
/*static*/ void ClientCursor::assertNoCursors() {
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
return byLoc.size();
|
||||
if( clientCursorsById.size() ) {
|
||||
log() << "ERROR clientcursors exist but should not at this point" << endl;
|
||||
ClientCursor *cc = clientCursorsById.begin()->second;
|
||||
log() << "first one: " << cc->cursorid << ' ' << cc->ns << endl;
|
||||
clientCursorsById.clear();
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClientCursor::setLastLoc_inlock(DiskLoc L) {
|
||||
if ( L == _lastLoc )
|
||||
return;
|
||||
|
||||
CCByLoc& bl = byLoc();
|
||||
if ( !_lastLoc.isNull() ) {
|
||||
CCByLoc::iterator i = kv_find(byLoc, _lastLoc, this);
|
||||
if ( i != byLoc.end() )
|
||||
byLoc.erase(i);
|
||||
CCByLoc::iterator i = kv_find(bl, _lastLoc, this);
|
||||
if ( i != bl.end() )
|
||||
bl.erase(i);
|
||||
}
|
||||
|
||||
if ( !L.isNull() )
|
||||
byLoc.insert( make_pair(L, this) );
|
||||
bl.insert( make_pair(L, this) );
|
||||
_lastLoc = L;
|
||||
}
|
||||
|
||||
@@ -76,24 +86,52 @@ namespace mongo {
|
||||
{
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
|
||||
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); ++i ) {
|
||||
Database *db = cc().database();
|
||||
assert(db);
|
||||
assert( str::startsWith(nsPrefix, db->name) );
|
||||
|
||||
for( CCById::iterator i = clientCursorsById.begin(); i != clientCursorsById.end(); ++i ) {
|
||||
ClientCursor *cc = i->second;
|
||||
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 )
|
||||
if( cc->_db != db )
|
||||
continue;
|
||||
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 ) {
|
||||
toDelete.push_back(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
note : we can't iterate byloc because clientcursors may exist with a loc of null in which case
|
||||
they are not in the map. perhaps they should not exist though in the future? something to
|
||||
change???
|
||||
|
||||
CCByLoc& bl = db->ccByLoc;
|
||||
for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); ++i ) {
|
||||
ClientCursor *cc = i->second;
|
||||
if ( strncmp(nsPrefix, cc->ns.c_str(), len) == 0 ) {
|
||||
assert( cc->_db == db );
|
||||
toDelete.push_back(i->second);
|
||||
}
|
||||
}*/
|
||||
|
||||
for ( vector<ClientCursor*>::iterator i = toDelete.begin(); i != toDelete.end(); ++i )
|
||||
delete (*i);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClientCursor::shouldTimeout( unsigned millis ){
|
||||
_idleAgeMillis += millis;
|
||||
return _idleAgeMillis > 600000 && _pinValue == 0;
|
||||
}
|
||||
|
||||
/* called every 4 seconds. millis is amount of idle time passed since the last call -- could be zero */
|
||||
void ClientCursor::idleTimeReport(unsigned millis) {
|
||||
readlock lk("");
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); ) {
|
||||
CCByLoc::iterator j = i;
|
||||
for ( CCById::iterator i = clientCursorsById.begin(); i != clientCursorsById.end(); ) {
|
||||
CCById::iterator j = i;
|
||||
i++;
|
||||
if( j->second->shouldTimeout( millis ) ){
|
||||
numberTimedOut++;
|
||||
log(1) << "killing old cursor " << j->second->cursorid << ' ' << j->second->ns
|
||||
<< " idle:" << j->second->idleTime() << "ms\n";
|
||||
delete j->second;
|
||||
@@ -106,10 +144,12 @@ namespace mongo {
|
||||
*/
|
||||
void ClientCursor::informAboutToDeleteBucket(const DiskLoc& b) {
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
RARELY if ( byLoc.size() > 70 ) {
|
||||
log() << "perf warning: byLoc.size=" << byLoc.size() << " in aboutToDeleteBucket\n";
|
||||
Database *db = cc().database();
|
||||
CCByLoc& bl = db->ccByLoc;
|
||||
RARELY if ( bl.size() > 70 ) {
|
||||
log() << "perf warning: byLoc.size=" << bl.size() << " in aboutToDeleteBucket\n";
|
||||
}
|
||||
for ( CCByLoc::iterator i = byLoc.begin(); i != byLoc.end(); i++ )
|
||||
for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); i++ )
|
||||
i->second->c->aboutToDeleteBucket(b);
|
||||
}
|
||||
void aboutToDeleteBucket(const DiskLoc& b) {
|
||||
@@ -120,8 +160,11 @@ namespace mongo {
|
||||
void ClientCursor::aboutToDelete(const DiskLoc& dl) {
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
|
||||
CCByLoc::iterator j = byLoc.lower_bound(dl);
|
||||
CCByLoc::iterator stop = byLoc.upper_bound(dl);
|
||||
Database *db = cc().database();
|
||||
assert(db);
|
||||
CCByLoc& bl = db->ccByLoc;
|
||||
CCByLoc::iterator j = bl.lower_bound(dl);
|
||||
CCByLoc::iterator stop = bl.upper_bound(dl);
|
||||
if ( j == stop )
|
||||
return;
|
||||
|
||||
@@ -139,6 +182,7 @@ namespace mongo {
|
||||
|
||||
for ( vector<ClientCursor*>::iterator i = toAdvance.begin(); i != toAdvance.end(); ++i ){
|
||||
ClientCursor* cc = *i;
|
||||
wassert(cc->_db == db);
|
||||
|
||||
if ( cc->_doingDeletes ) continue;
|
||||
|
||||
@@ -157,7 +201,9 @@ namespace mongo {
|
||||
c->advance();
|
||||
if ( c->eof() ) {
|
||||
// advanced to end
|
||||
// leave ClieneCursor in place so next getMore doesn't fail
|
||||
// leave ClientCursor in place so next getMore doesn't fail
|
||||
// still need to mark new location though
|
||||
cc->updateLocation();
|
||||
}
|
||||
else {
|
||||
wassert( c->refLoc() != dl );
|
||||
@@ -296,6 +342,13 @@ namespace mongo {
|
||||
|
||||
int ctmLast = 0; // so we don't have to do find() which is a little slow very often.
|
||||
long long ClientCursor::allocCursorId_inlock() {
|
||||
if( 0 ) {
|
||||
static long long z;
|
||||
++z;
|
||||
cout << "TEMP alloccursorid " << z << endl;
|
||||
return z;
|
||||
}
|
||||
|
||||
long long x;
|
||||
int ctm = (int) curTimeMillis();
|
||||
while ( 1 ) {
|
||||
@@ -328,7 +381,13 @@ namespace mongo {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClientCursor::appendStats( BSONObjBuilder& result ){
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
result.appendNumber("totalOpen", (int)clientCursorsById.size() );
|
||||
result.appendNumber("clientCursors_size", (int) numCursors());
|
||||
result.appendNumber("timedOut" , (int)numberTimedOut);
|
||||
}
|
||||
|
||||
// QUESTION: Restrict to the namespace from which this command was issued?
|
||||
// Alternatively, make this command admin-only?
|
||||
class CmdCursorInfo : public Command {
|
||||
@@ -339,11 +398,8 @@ namespace mongo {
|
||||
help << " example: { cursorInfo : 1 }";
|
||||
}
|
||||
virtual LockType locktype() const { return NONE; }
|
||||
bool run(const string&, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
recursive_scoped_lock lock(ClientCursor::ccmutex);
|
||||
result.append("totalOpen", unsigned( ClientCursor::clientCursorsById.size() ) );
|
||||
result.append("byLocation_size", unsigned( ClientCursor::byLoc.size() ) );
|
||||
result.append("clientCursors_size", unsigned( ClientCursor::clientCursorsById.size() ) );
|
||||
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
ClientCursor::appendStats( result );
|
||||
return true;
|
||||
}
|
||||
} cmdCursorInfo;
|
||||
|
||||
@@ -45,8 +45,6 @@ namespace mongo {
|
||||
*/
|
||||
typedef map<CursorId, ClientCursor*> CCById;
|
||||
|
||||
typedef multimap<DiskLoc, ClientCursor*> CCByLoc;
|
||||
|
||||
extern BSONObj id_obj;
|
||||
|
||||
class ClientCursor {
|
||||
@@ -64,14 +62,13 @@ namespace mongo {
|
||||
ElapsedTracker _yieldSometimesTracker;
|
||||
|
||||
static CCById clientCursorsById;
|
||||
static CCByLoc byLoc;
|
||||
static boost::recursive_mutex ccmutex; // must use this for all statics above!
|
||||
|
||||
static CursorId allocCursorId_inlock();
|
||||
|
||||
|
||||
static long long numberTimedOut;
|
||||
static boost::recursive_mutex ccmutex; // must use this for all statics above!
|
||||
static CursorId allocCursorId_inlock();
|
||||
|
||||
public:
|
||||
static void assertNoCursors();
|
||||
|
||||
/* use this to assure we don't in the background time out cursor while it is under use.
|
||||
if you are using noTimeout() already, there is no risk anyway.
|
||||
Further, this mechanism guards against two getMore requests on the same cursor executing
|
||||
@@ -139,19 +136,23 @@ namespace mongo {
|
||||
};
|
||||
|
||||
/*const*/ CursorId cursorid;
|
||||
string ns;
|
||||
shared_ptr<Cursor> c;
|
||||
const string ns;
|
||||
const shared_ptr<Cursor> c;
|
||||
int pos; // # objects into the cursor so far
|
||||
BSONObj query;
|
||||
int _queryOptions; // see enum QueryOptions dbclient.h
|
||||
const int _queryOptions; // see enum QueryOptions dbclient.h
|
||||
OpTime _slaveReadTill;
|
||||
Database * const _db;
|
||||
|
||||
ClientCursor(int queryOptions, shared_ptr<Cursor>& _c, const string& _ns) :
|
||||
_idleAgeMillis(0), _pinValue(0),
|
||||
_doingDeletes(false), _yieldSometimesTracker(128,10),
|
||||
ns(_ns), c(_c),
|
||||
pos(0), _queryOptions(queryOptions)
|
||||
pos(0), _queryOptions(queryOptions),
|
||||
_db( cc().database() )
|
||||
{
|
||||
assert( _db );
|
||||
assert( str::startsWith(_ns, _db->name) );
|
||||
if( queryOptions & QueryOption_NoCursorTimeout )
|
||||
noTimeout();
|
||||
recursive_scoped_lock lock(ccmutex);
|
||||
@@ -308,10 +309,7 @@ namespace mongo {
|
||||
/**
|
||||
* @param millis amount of idle passed time since last call
|
||||
*/
|
||||
bool shouldTimeout( unsigned millis ){
|
||||
_idleAgeMillis += millis;
|
||||
return _idleAgeMillis > 600000 && _pinValue == 0;
|
||||
}
|
||||
bool shouldTimeout( unsigned millis );
|
||||
|
||||
void storeOpForSlave( DiskLoc last );
|
||||
void updateSlaveLocation( CurOp& curop );
|
||||
@@ -327,12 +325,18 @@ private:
|
||||
void noTimeout() {
|
||||
_pinValue++;
|
||||
}
|
||||
|
||||
multimap<DiskLoc, ClientCursor*>& byLoc() {
|
||||
return _db->ccByLoc;
|
||||
}
|
||||
public:
|
||||
void setDoingDeletes( bool doingDeletes ){
|
||||
_doingDeletes = doingDeletes;
|
||||
}
|
||||
|
||||
static void appendStats( BSONObjBuilder& result );
|
||||
|
||||
static unsigned byLocSize(); // just for diagnostics
|
||||
static unsigned numCursors() { return clientCursorsById.size(); }
|
||||
|
||||
static void informAboutToDeleteBucket(const DiskLoc& b);
|
||||
static void aboutToDelete(const DiskLoc& dl);
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace mongo {
|
||||
("bind_ip", po::value<string>(&cmdLine.bind_ip), "comma separated list of ip addresses to listen on - all local ips by default")
|
||||
("logpath", po::value<string>() , "file to send all output to instead of stdout" )
|
||||
("logappend" , "append to logpath instead of over-writing" )
|
||||
("pidfilepath", po::value<string>(), "directory for pidfile (if not set, no pidfile is created)")
|
||||
("pidfilepath", po::value<string>(), "full path to pidfile (if not set, no pidfile is created)")
|
||||
#ifndef _WIN32
|
||||
("fork" , "fork server process" )
|
||||
#endif
|
||||
|
||||
@@ -85,13 +85,7 @@ namespace mongo {
|
||||
int querySize() const { return *((int *) _queryBuf); }
|
||||
bool haveQuery() const { return querySize() != 0; }
|
||||
|
||||
BSONObj query() {
|
||||
if( querySize() == 1 ) {
|
||||
return _tooBig;
|
||||
}
|
||||
BSONObj o(_queryBuf);
|
||||
return o;
|
||||
}
|
||||
BSONObj query( bool threadSafe = false);
|
||||
|
||||
void ensureStarted(){
|
||||
if ( _start == 0 )
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
namespace mongo {
|
||||
|
||||
class ClientCursor;
|
||||
|
||||
/**
|
||||
* Database represents a database database
|
||||
* Each database database has its own set of files -- dbname.ns, dbname.0, dbname.1, ...
|
||||
@@ -196,6 +198,9 @@ namespace mongo {
|
||||
NamespaceIndex namespaceIndex;
|
||||
int profile; // 0=off.
|
||||
string profileName; // "alleyinsider.system.profile"
|
||||
|
||||
multimap<DiskLoc, ClientCursor*> ccByLoc;
|
||||
|
||||
int magic; // used for making sure the object is still loaded in memory
|
||||
};
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace mongo {
|
||||
assert( sprintf( buf , "w block pass: %lld" , ++passes ) < 30 );
|
||||
c.curop()->setMessage( buf );
|
||||
sleepmillis(1);
|
||||
killCurrentOp.checkForInterrupt();
|
||||
}
|
||||
result.appendNumber( "wtime" , t.millis() );
|
||||
}
|
||||
@@ -159,32 +160,6 @@ namespace mongo {
|
||||
}
|
||||
} cmdGetPrevError;
|
||||
|
||||
class CmdSwitchToClientErrors : public Command {
|
||||
public:
|
||||
virtual bool requiresAuth() { return false; }
|
||||
virtual bool logTheOp() {
|
||||
return false;
|
||||
}
|
||||
virtual void help( stringstream& help ) const {
|
||||
help << "convert to id based errors rather than connection based";
|
||||
}
|
||||
virtual bool slaveOk() const {
|
||||
return true;
|
||||
}
|
||||
virtual LockType locktype() const { return NONE; }
|
||||
CmdSwitchToClientErrors() : Command("switchToClientErrors", false, "switchtoclienterrors") {}
|
||||
bool run(const string& dbnamne , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
|
||||
if ( lastError.getID() ){
|
||||
errmsg = "already in client id mode";
|
||||
return false;
|
||||
}
|
||||
LastError *le = lastError.disableForCommand();
|
||||
le->overridenById = true;
|
||||
result << "ok" << 1;
|
||||
return true;
|
||||
}
|
||||
} cmdSwitchToClientErrors;
|
||||
|
||||
class CmdDropDatabase : public Command {
|
||||
public:
|
||||
virtual bool logTheOp() {
|
||||
@@ -292,7 +267,6 @@ namespace mongo {
|
||||
}
|
||||
|
||||
bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
|
||||
|
||||
long long start = Listener::getElapsedTimeMillis();
|
||||
BSONObjBuilder timeBuilder(128);
|
||||
|
||||
@@ -381,7 +355,13 @@ namespace mongo {
|
||||
globalFlushCounters.append( bb );
|
||||
bb.done();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
BSONObjBuilder bb( result.subobjStart( "cursros" ) );
|
||||
ClientCursor::appendStats( bb );
|
||||
bb.done();
|
||||
}
|
||||
|
||||
timeBuilder.appendNumber( "after counters" , Listener::getElapsedTimeMillis() - start );
|
||||
|
||||
if ( anyReplEnabled() ){
|
||||
@@ -648,10 +628,10 @@ namespace mongo {
|
||||
virtual void help( stringstream& help ) const {
|
||||
help << "create a collection";
|
||||
}
|
||||
virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
|
||||
virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
|
||||
string ns = dbname + '.' + cmdObj.firstElement().valuestr();
|
||||
string err;
|
||||
bool ok = userCreateNS(ns.c_str(), cmdObj, err, true);
|
||||
bool ok = userCreateNS(ns.c_str(), cmdObj, err, ! fromRepl );
|
||||
if ( !ok && !err.empty() )
|
||||
errmsg = err;
|
||||
return ok;
|
||||
@@ -1450,17 +1430,18 @@ namespace mongo {
|
||||
|
||||
BSONElementSet values;
|
||||
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
|
||||
scoped_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns));
|
||||
|
||||
while ( cursor->ok() ){
|
||||
if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
cursor->advance();
|
||||
continue;
|
||||
if ( !cursor->matcher() || cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
BSONObj o = cursor->current();
|
||||
o.getFieldsDotted( key, values );
|
||||
}
|
||||
|
||||
BSONObj o = cursor->current();
|
||||
cursor->advance();
|
||||
|
||||
o.getFieldsDotted( key.c_str(), values );
|
||||
|
||||
if (!cc->yieldSometimes())
|
||||
break;
|
||||
}
|
||||
|
||||
BSONArrayBuilder b( result.subarrayStart( "values" ) );
|
||||
|
||||
@@ -60,6 +60,13 @@ namespace mongo {
|
||||
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
result << "version" << versionString << "gitVersion" << gitVersion() << "sysInfo" << sysInfo();
|
||||
result << "bits" << ( sizeof( int* ) == 4 ? 32 : 64 );
|
||||
result.appendBool( "debug" ,
|
||||
#ifdef _DEBUG
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
return true;
|
||||
}
|
||||
} cmdBuildInfo;
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace mongo {
|
||||
ss << p( a("/", "back", "Home") );
|
||||
ss << p( "<b>MongoDB List of <a href=\"http://www.mongodb.org/display/DOCS/Commands\">Commands</a></b>\n" );
|
||||
const map<string, Command*> *m = Command::commandsByBestName();
|
||||
ss << "S:slave-only N:no-lock R:read-lock W:write-lock A:admin-only<br>\n";
|
||||
ss << "S:slave-ok R:read-lock W:write-lock A:admin-only<br>\n";
|
||||
ss << table();
|
||||
ss << "<tr><th>Command</th><th>Attributes</th><th>Help</th></tr>\n";
|
||||
for( map<string, Command*>::const_iterator i = m->begin(); i != m->end(); i++ )
|
||||
|
||||
@@ -143,6 +143,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
virtual ConnectionString::ConnectionType type() const { return ConnectionString::MASTER; }
|
||||
virtual bool isMember( const DBConnector * conn ) const { return this == conn; };
|
||||
};
|
||||
|
||||
extern int lockFile;
|
||||
|
||||
@@ -168,9 +168,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
LastError * LastErrorHolder::startRequest( Message& m , int clientId ) {
|
||||
|
||||
if ( clientId == 0 )
|
||||
clientId = m.header()->id & 0xFFFF0000;
|
||||
assert( clientId );
|
||||
setID( clientId );
|
||||
|
||||
LastError * le = _get( true );
|
||||
@@ -179,11 +177,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
void LastErrorHolder::startRequest( Message& m , LastError * connectionOwned ) {
|
||||
if ( !connectionOwned->overridenById ) {
|
||||
prepareErrForNewRequest( m, connectionOwned );
|
||||
return;
|
||||
}
|
||||
startRequest(m);
|
||||
prepareErrForNewRequest( m, connectionOwned );
|
||||
}
|
||||
|
||||
void LastErrorHolder::disconnect( int clientId ){
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace mongo {
|
||||
long long nObjects;
|
||||
int nPrev;
|
||||
bool valid;
|
||||
bool overridenById;
|
||||
bool disabled;
|
||||
void writeback( OID& oid ){
|
||||
reset( true );
|
||||
@@ -56,7 +55,6 @@ namespace mongo {
|
||||
nObjects = nDeleted;
|
||||
}
|
||||
LastError() {
|
||||
overridenById = false;
|
||||
reset();
|
||||
}
|
||||
void reset( bool _valid = false ) {
|
||||
@@ -127,7 +125,7 @@ namespace mongo {
|
||||
|
||||
/** when db receives a message/request, call this */
|
||||
void startRequest( Message& m , LastError * connectionOwned );
|
||||
LastError * startRequest( Message& m , int clientId = 0 );
|
||||
LastError * startRequest( Message& m , int clientId );
|
||||
|
||||
void disconnect( int clientId );
|
||||
|
||||
|
||||
10
db/mr.cpp
10
db/mr.cpp
@@ -176,11 +176,11 @@ namespace mongo {
|
||||
{ // query options
|
||||
if ( cmdObj["query"].type() == Object ){
|
||||
filter = cmdObj["query"].embeddedObjectUserCheck();
|
||||
q = filter;
|
||||
}
|
||||
|
||||
if ( cmdObj["sort"].type() == Object )
|
||||
q.sort( cmdObj["sort"].embeddedObjectUserCheck() );
|
||||
if ( cmdObj["sort"].type() == Object ){
|
||||
sort = cmdObj["sort"].embeddedObjectUserCheck();
|
||||
}
|
||||
|
||||
if ( cmdObj["limit"].isNumber() )
|
||||
limit = cmdObj["limit"].numberLong();
|
||||
@@ -222,7 +222,7 @@ namespace mongo {
|
||||
// query options
|
||||
|
||||
BSONObj filter;
|
||||
Query q;
|
||||
BSONObj sort;
|
||||
long long limit;
|
||||
|
||||
// functions
|
||||
@@ -444,7 +444,7 @@ namespace mongo {
|
||||
readlock lock( mr.ns );
|
||||
Client::Context ctx( mr.ns );
|
||||
|
||||
shared_ptr<Cursor> temp = bestGuessCursor( mr.ns.c_str(), mr.filter, BSONObj() );
|
||||
shared_ptr<Cursor> temp = bestGuessCursor( mr.ns.c_str(), mr.filter, mr.sort );
|
||||
auto_ptr<ClientCursor> cursor( new ClientCursor( QueryOption_NoCursorTimeout , temp , mr.ns.c_str() ) );
|
||||
|
||||
Timer mt;
|
||||
|
||||
@@ -637,6 +637,8 @@ namespace mongo {
|
||||
}
|
||||
|
||||
bool legalClientSystemNS( const string& ns , bool write ){
|
||||
if( ns == "local.system.replset" ) return true;
|
||||
|
||||
if ( ns.find( ".system.users" ) != string::npos )
|
||||
return true;
|
||||
|
||||
|
||||
@@ -728,8 +728,11 @@ namespace mongo {
|
||||
try {
|
||||
assert( dropIndexes(d, name.c_str(), "*", errmsg, result, true) );
|
||||
}
|
||||
catch( DBException& ) {
|
||||
uasserted(12503,"drop: dropIndexes for collection failed - consider trying repair");
|
||||
catch( DBException& e ) {
|
||||
stringstream ss;
|
||||
ss << "drop: dropIndexes for collection failed - consider trying repair ";
|
||||
ss << " cause: " << e.what();
|
||||
uasserted(12503,ss.str());
|
||||
}
|
||||
assert( d->nIndexes == 0 );
|
||||
}
|
||||
@@ -1892,7 +1895,10 @@ namespace mongo {
|
||||
bb.done();
|
||||
if( nNotClosed )
|
||||
result.append("nNotClosed", nNotClosed);
|
||||
|
||||
else {
|
||||
ClientCursor::assertNoCursors();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -654,11 +654,12 @@ namespace mongo {
|
||||
if ( !ClientCursor::recoverFromYield( _yieldData ) ) {
|
||||
_c.reset();
|
||||
_cc.reset();
|
||||
_so.reset();
|
||||
massert( 13338, "cursor dropped during query", false );
|
||||
// TODO maybe we want to prevent recording the winning plan as well?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void next() {
|
||||
if ( _findingStartCursor.get() ) {
|
||||
@@ -772,7 +773,8 @@ namespace mongo {
|
||||
_n = _inMemSort ? _so->size() : _n;
|
||||
}
|
||||
else if ( _inMemSort ) {
|
||||
_so->fill( _buf, _pq.getFields() , _n );
|
||||
if( _so.get() )
|
||||
_so->fill( _buf, _pq.getFields() , _n );
|
||||
}
|
||||
|
||||
if ( _pq.hasOption( QueryOption_CursorTailable ) && _pq.getNumToReturn() != 1 )
|
||||
|
||||
27
db/repl.cpp
27
db/repl.cpp
@@ -290,11 +290,13 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.append("ismaster", replSettings.master || replSettings.slave == 0 ? 1 : 0);
|
||||
//result.append("msg", "not paired");
|
||||
result.appendBool("ismaster", _isMaster() );
|
||||
}
|
||||
|
||||
if ( level ){
|
||||
|
||||
if ( level && replSet ){
|
||||
result.append( "info" , "is replica set" );
|
||||
}
|
||||
else if ( level ){
|
||||
BSONObjBuilder sources( result.subarrayStart( "sources" ) );
|
||||
|
||||
readlock lk( "local.sources" );
|
||||
@@ -856,11 +858,13 @@ namespace mongo {
|
||||
see logOp() comments.
|
||||
*/
|
||||
void ReplSource::sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTail) {
|
||||
log( 6 ) << "processing op: " << op << endl;
|
||||
if( logLevel >= 6 ) // op.tostring is expensive so doing this check explicitly
|
||||
log(6) << "processing op: " << op << endl;
|
||||
|
||||
// skip no-op
|
||||
if ( op.getStringField( "op" )[ 0 ] == 'n' )
|
||||
if( op.getStringField("op")[0] == 'n' )
|
||||
return;
|
||||
|
||||
|
||||
char clientName[MaxDatabaseLen];
|
||||
const char *ns = op.getStringField("ns");
|
||||
nsToDatabase(ns, clientName);
|
||||
@@ -1301,12 +1305,15 @@ namespace mongo {
|
||||
1) find most recent op in local log
|
||||
2) more()?
|
||||
*/
|
||||
if ( !oplogReader.more() ) {
|
||||
|
||||
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;
|
||||
OpTime nextLastSaved = nextLastSavedLocalTs();
|
||||
{
|
||||
dbtemprelease t;
|
||||
if ( oplogReader.more() ) {
|
||||
if ( !moreInitialSyncsPending && oplogReader.more() ) {
|
||||
if ( getInitialSyncCompleted() ) { // if initial sync hasn't completed, break out of loop so we can set to completed or clone more dbs
|
||||
continue;
|
||||
}
|
||||
@@ -1323,6 +1330,8 @@ namespace mongo {
|
||||
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
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
void ReplSetImpl::_getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) const {
|
||||
Member *m = findById(server_id);
|
||||
const Member *m = findById(server_id);
|
||||
if( m == 0 ) {
|
||||
ss << "Error : can't find a member with id: " << server_id << '\n';
|
||||
return;
|
||||
@@ -329,7 +329,7 @@ namespace mongo {
|
||||
_rsLog.toHTML( s );
|
||||
}
|
||||
|
||||
Member* ReplSetImpl::findById(unsigned id) const {
|
||||
const Member* ReplSetImpl::findById(unsigned id) const {
|
||||
if( id == _self->id() ) return _self;
|
||||
for( Member *m = head(); m; m = m->next() )
|
||||
if( m->id() == id )
|
||||
@@ -371,6 +371,7 @@ namespace mongo {
|
||||
v.push_back(bb.obj());
|
||||
m = m->next();
|
||||
}
|
||||
sort(v.begin(), v.end());
|
||||
b.append("set", name());
|
||||
b.appendTimeT("date", time(0));
|
||||
b.append("myState", box.getState().s);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
namespace mongo {
|
||||
|
||||
void checkAllMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial);
|
||||
void checkMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial);
|
||||
|
||||
/* commands in other files:
|
||||
replSetHeartbeat - health.cpp
|
||||
@@ -151,9 +151,9 @@ namespace mongo {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkAllMembersUpForConfigChange(newConfig,false);
|
||||
checkMembersUpForConfigChange(newConfig,false);
|
||||
|
||||
log() << "replSet replSetReconfig all members seem up" << rsLog;
|
||||
log() << "replSet replSetReconfig [2]" << rsLog;
|
||||
|
||||
theReplSet->haveNewConfig(newConfig, true);
|
||||
ReplSet::startupStatusMsg = "replSetReconfig'd";
|
||||
|
||||
@@ -123,6 +123,7 @@ namespace mongo {
|
||||
void ReplSetImpl::_fillIsMaster(BSONObjBuilder& b) {
|
||||
const StateBox::SP sp = box.get();
|
||||
bool isp = sp.state.primary();
|
||||
b.append("setName", name());
|
||||
b.append("ismaster", isp);
|
||||
b.append("secondary", sp.state.secondary());
|
||||
{
|
||||
@@ -390,9 +391,9 @@ namespace mongo {
|
||||
startupStatus = EMPTYCONFIG;
|
||||
startupStatusMsg = "can't get " + rsConfigNs + " config from self or any seed (EMPTYCONFIG)";
|
||||
log() << "replSet can't get " << rsConfigNs << " config from self or any seed (EMPTYCONFIG)" << rsLog;
|
||||
log() << "replSet have you ran replSetInitiate yet?" << rsLog;
|
||||
log(1) << "replSet have you ran replSetInitiate yet?" << rsLog;
|
||||
if( _seeds->size() == 0 )
|
||||
log() << "replSet no seed hosts were specified on the --replSet command line - that might be the issue" << rsLog;
|
||||
log(1) << "replSet info no seed hosts were specified on the --replSet command line" << rsLog;
|
||||
}
|
||||
else {
|
||||
startupStatus = EMPTYUNREACHABLE;
|
||||
|
||||
@@ -305,7 +305,9 @@ namespace mongo {
|
||||
|
||||
private:
|
||||
Member* head() const { return _members.head(); }
|
||||
Member* findById(unsigned id) const;
|
||||
public:
|
||||
const Member* findById(unsigned id) const;
|
||||
private:
|
||||
void _getTargets(list<Target>&, int &configVersion);
|
||||
void getTargets(list<Target>&, int &configVersion);
|
||||
void startThreads();
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace mongo {
|
||||
mchk(_id >= 0 && _id <= 255);
|
||||
mchk(priority >= 0 && priority <= 1000);
|
||||
mchk(votes >= 0 && votes <= 100);
|
||||
uassert(13419, "replica set config : this version of mongo only supports priorities 0 and 1", priority == 0 || priority == 1);
|
||||
uassert(13419, "this version of mongod only supports priorities 0 and 1", priority == 0 || priority == 1);
|
||||
}
|
||||
|
||||
/*static*/ bool ReplSetConfig::legalChange(const ReplSetConfig& o, const ReplSetConfig& n, string& errmsg) {
|
||||
@@ -133,7 +133,7 @@ namespace mongo {
|
||||
|
||||
/* TODO : MORE CHECKS HERE */
|
||||
|
||||
cout << "TODO : don't allow removal of a node until we handle it at the removed node end." << endl;
|
||||
log() << "replSet TODO : don't allow removal of a node until we handle it at the removed node end?" << endl;
|
||||
// we could change its votes to zero perhaps instead as a short term...
|
||||
|
||||
return true;
|
||||
@@ -220,7 +220,7 @@ namespace mongo {
|
||||
catch(DBException& e) {
|
||||
log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << rsLog;
|
||||
stringstream ss;
|
||||
ss << "replSet members[" << i << "] bad config object";
|
||||
ss << "bad config for member[" << i << "] " << e.what();
|
||||
uassert(13135, ss.str(), false);
|
||||
}
|
||||
if( !(ords.count(m._id) == 0 && hosts.count(m.h.toString()) == 0) ) {
|
||||
|
||||
@@ -32,10 +32,12 @@ using namespace mongoutils;
|
||||
|
||||
namespace mongo {
|
||||
|
||||
/* throws
|
||||
@param initial -
|
||||
/* called on a reconfig AND on initiate
|
||||
throws
|
||||
@param initial true when initiating
|
||||
*/
|
||||
void checkAllMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial) {
|
||||
void checkMembersUpForConfigChange(const ReplSetConfig& cfg, bool initial) {
|
||||
int failures = 0;
|
||||
int me = 0;
|
||||
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) {
|
||||
if( i->h.isSelf() ) {
|
||||
@@ -45,7 +47,7 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
}
|
||||
uassert(13278, "bad config?", me <= 1);
|
||||
uassert(13278, "bad config - dups?", me <= 1); // dups?
|
||||
uassert(13279, "can't find self in the replset config", me == 1);
|
||||
|
||||
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = cfg.members.begin(); i != cfg.members.end(); i++ ) {
|
||||
@@ -62,12 +64,11 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
catch(DBException& e) {
|
||||
log() << "replSet requestHeartbeat " << i->h.toString() << " : " << e.toString() << rsLog;
|
||||
log() << "replSet cmufcc requestHeartbeat " << i->h.toString() << " : " << e.toString() << rsLog;
|
||||
}
|
||||
catch(...) {
|
||||
log() << "replSet error exception in requestHeartbeat?" << rsLog;
|
||||
log() << "replSet cmufcc error exception in requestHeartbeat?" << rsLog;
|
||||
}
|
||||
cout << "TEMP hb res cfg change:" << res.toString() << endl;
|
||||
if( res.getBoolField("mismatch") )
|
||||
uasserted(13145, "set name does not match the set name host " + i->h.toString() + " expects");
|
||||
if( *res.getStringField("set") ) {
|
||||
@@ -83,9 +84,31 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
if( !ok && !res["rs"].trueValue() ) {
|
||||
if( !res.isEmpty() )
|
||||
if( !res.isEmpty() ) {
|
||||
/* strange. got a response, but not "ok". log it. */
|
||||
log() << "replSet warning " << i->h.toString() << " replied: " << res.toString() << rsLog;
|
||||
uasserted(13144, "need members up to initiate/reconfig, not ok: " + i->h.toString());
|
||||
}
|
||||
|
||||
bool allowFailure = false;
|
||||
failures++;
|
||||
if( res.isEmpty() && !initial && failures == 1 ) {
|
||||
/* for now we are only allowing 1 node to be down on a reconfig. this can be made to be a minority
|
||||
trying to keep change small as release is near.
|
||||
*/
|
||||
const Member* m = theReplSet->findById( i->_id );
|
||||
if( m ) {
|
||||
// ok, so this was an existing member (wouldn't make sense to add to config a new member that is down)
|
||||
assert( m->h().toString() == i->h.toString() );
|
||||
allowFailure = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !allowFailure ) {
|
||||
string msg = string("need members up to initiate, not ok : ") + i->h.toString();
|
||||
if( !initial )
|
||||
msg = string("need most members up to reconfigure, not ok : ") + i->h.toString();
|
||||
uasserted(13144, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
if( initial ) {
|
||||
@@ -175,8 +198,10 @@ namespace mongo {
|
||||
configObj = cmdObj["replSetInitiate"].Obj();
|
||||
}
|
||||
|
||||
bool parsed = false;
|
||||
try {
|
||||
ReplSetConfig newConfig(configObj);
|
||||
parsed = true;
|
||||
|
||||
if( newConfig.version > 1 ) {
|
||||
errmsg = "can't initiate with a version number greater than 1";
|
||||
@@ -185,7 +210,7 @@ namespace mongo {
|
||||
|
||||
log() << "replSet replSetInitiate config object parses ok, " << newConfig.members.size() << " members specified" << rsLog;
|
||||
|
||||
checkAllMembersUpForConfigChange(newConfig, true);
|
||||
checkMembersUpForConfigChange(newConfig, true);
|
||||
|
||||
log() << "replSet replSetInitiate all members seem up" << rsLog;
|
||||
|
||||
@@ -199,7 +224,11 @@ namespace mongo {
|
||||
}
|
||||
catch( DBException& e ) {
|
||||
log() << "replSet replSetInitiate exception: " << e.what() << rsLog;
|
||||
throw;
|
||||
if( !parsed )
|
||||
errmsg = string("couldn't parse cfg object ") + e.what();
|
||||
else
|
||||
errmsg = string("couldn't initiate : ") + e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -203,8 +203,8 @@ namespace mongo {
|
||||
OpTime ts = o["ts"]._opTime();
|
||||
long long h = o["h"].numberLong();
|
||||
if( ts != lastOpTimeWritten || h != lastH ) {
|
||||
log() << "TEMP our last op time written: " << lastOpTimeWritten.toStringPretty() << endl;
|
||||
log() << "TEMP primary's GTE: " << ts.toStringPretty() << endl;
|
||||
log(1) << "TEMP our last op time written: " << lastOpTimeWritten.toStringPretty() << endl;
|
||||
log(1) << "TEMP primary's GTE: " << ts.toStringPretty() << endl;
|
||||
/*
|
||||
}*/
|
||||
|
||||
@@ -243,7 +243,6 @@ namespace mongo {
|
||||
}
|
||||
else {
|
||||
sethbmsg(str::stream() << "still syncing, not yet to minValid optime " << minvalid.toString());
|
||||
//log() << "TEMP " << lastOpTimeWritten.toString() << rsLog;
|
||||
}
|
||||
|
||||
/* todo: too stale capability */
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace mongo {
|
||||
if( replSet ) {
|
||||
/* todo: speed up the secondary case. as written here there are 2 mutex entries, it can be 1. */
|
||||
if( isMaster() ) return;
|
||||
notMasterUnless( pq.hasOption(QueryOption_SlaveOk) && theReplSet->isSecondary() );
|
||||
notMasterUnless( pq.hasOption(QueryOption_SlaveOk) && theReplSet && theReplSet->isSecondary() );
|
||||
} else {
|
||||
notMasterUnless(isMaster() || pq.hasOption(QueryOption_SlaveOk) || replSettings.slave == SimpleSlave );
|
||||
}
|
||||
|
||||
@@ -266,8 +266,8 @@ namespace mongo {
|
||||
|
||||
ss << "# databases: " << dbHolder.size() << '\n';
|
||||
|
||||
if( ClientCursor::byLocSize()>500 )
|
||||
ss << "Cursors byLoc.size(): " << ClientCursor::byLocSize() << '\n';
|
||||
if( ClientCursor::numCursors()>500 )
|
||||
ss << "# Cursors: " << ClientCursor::numCursors() << '\n';
|
||||
|
||||
ss << "\nreplication: ";
|
||||
if( *replInfo )
|
||||
|
||||
@@ -88,16 +88,17 @@ namespace mongo {
|
||||
|
||||
void _add(BSONObj& k, BSONObj o, DiskLoc* loc) {
|
||||
if (!loc){
|
||||
best.insert(make_pair(k,o));
|
||||
best.insert(make_pair(k.getOwned(),o.getOwned()));
|
||||
} else {
|
||||
BSONObjBuilder b;
|
||||
b.appendElements(o);
|
||||
b.append("$diskLoc", loc->toBSONObj());
|
||||
best.insert(make_pair(k, b.obj()));
|
||||
best.insert(make_pair(k.getOwned(), b.obj().getOwned()));
|
||||
}
|
||||
}
|
||||
|
||||
void _addIfBetter(BSONObj& k, BSONObj o, BestMap::iterator i, DiskLoc* loc) {
|
||||
/* todo : we don't correct approxSize here. */
|
||||
const BSONObj& worstBestKey = i->first;
|
||||
int c = worstBestKey.woCompare(k, order.pattern);
|
||||
if ( c > 0 ) {
|
||||
@@ -124,7 +125,11 @@ namespace mongo {
|
||||
BSONObj k = order.getKeyFromObject(o);
|
||||
if ( (int) best.size() < limit ) {
|
||||
approxSize += k.objsize();
|
||||
uassert( 10128 , "too much key data for sort() with no index. add an index or specify a smaller limit", approxSize < 1 * 1024 * 1024 );
|
||||
approxSize += o.objsize();
|
||||
|
||||
/* note : adjust when bson return limit adjusts. note this limit should be a bit higher. */
|
||||
uassert( 10128 , "too much data for sort() with no index. add an index or specify a smaller limit", approxSize < 32 * 1024 * 1024 );
|
||||
|
||||
_add(k, o, loc);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ namespace mongo {
|
||||
string field = root + e.fieldName();
|
||||
FieldCompareResult cmp = compareDottedFieldNames( m->second.m->fieldName , field );
|
||||
|
||||
DEBUGUPDATE( "\t\t\t field:" << field << "\t mod:" << m->second.m->fieldName << "\t cmp:" << cmp );
|
||||
DEBUGUPDATE( "\t\t\t field:" << field << "\t mod:" << m->second.m->fieldName << "\t cmp:" << cmp << "\t short: " << e.fieldName() );
|
||||
|
||||
switch ( cmp ){
|
||||
|
||||
@@ -550,6 +550,13 @@ namespace mongo {
|
||||
e = es.next();
|
||||
m++;
|
||||
}
|
||||
else {
|
||||
// this is a very weird case
|
||||
// have seen it in production, but can't reproduce
|
||||
// this assert prevents an inf. loop
|
||||
// but likely isn't the correct solution
|
||||
assert(0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case LEFT_BEFORE: // Mod on a field that doesn't exist
|
||||
@@ -613,6 +620,8 @@ namespace mongo {
|
||||
BSONObjIteratorSorted i( query );
|
||||
while ( i.more() ){
|
||||
BSONElement e = i.next();
|
||||
if ( e.fieldName()[0] == '$' ) // for $atomic and anything else we add
|
||||
continue;
|
||||
|
||||
if ( e.type() == Object && e.embeddedObject().firstElement().fieldName()[0] == '$' ){
|
||||
// this means this is a $gt type filter, so don't make part of the new object
|
||||
|
||||
@@ -389,6 +389,35 @@ namespace JsobjTests {
|
||||
}
|
||||
};
|
||||
|
||||
class ToStringNumber {
|
||||
public:
|
||||
|
||||
void run(){
|
||||
BSONObjBuilder b;
|
||||
b.append( "a" , (int)4 );
|
||||
b.append( "b" , (double)5 );
|
||||
b.append( "c" , (long long)6 );
|
||||
|
||||
b.append( "d" , 123.456789123456789123456789123456789 );
|
||||
b.append( "e" , 123456789.123456789123456789123456789 );
|
||||
b.append( "f" , 1234567891234567891234.56789123456789 );
|
||||
|
||||
b.append( "g" , -123.456 );
|
||||
|
||||
BSONObj x = b.obj();
|
||||
ASSERT_EQUALS( "4", x["a"].toString( false , true ) );
|
||||
ASSERT_EQUALS( "5.0", x["b"].toString( false , true ) );
|
||||
ASSERT_EQUALS( "6", x["c"].toString( false , true ) );
|
||||
|
||||
ASSERT_EQUALS( "123.4567891234568" , x["d"].toString( false , true ) );
|
||||
ASSERT_EQUALS( "123456789.1234568" , x["e"].toString( false , true ) );
|
||||
// ASSERT_EQUALS( "1.234567891234568e+21" , x["f"].toString( false , true ) ); // windows and *nix are different - TODO, work around for test or not bother?
|
||||
|
||||
ASSERT_EQUALS( "-123.456" , x["g"].toString( false , true ) );
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class NullString {
|
||||
public:
|
||||
void run() {
|
||||
@@ -1693,6 +1722,7 @@ namespace JsobjTests {
|
||||
add< BSONObjTests::AppendIntOrLL >();
|
||||
add< BSONObjTests::AppendNumber >();
|
||||
add< BSONObjTests::ToStringArray >();
|
||||
add< BSONObjTests::ToStringNumber >();
|
||||
add< BSONObjTests::NullString >();
|
||||
add< BSONObjTests::Validation::BadType >();
|
||||
add< BSONObjTests::Validation::EooBeforeEnd >();
|
||||
|
||||
25
debian/changelog
vendored
25
debian/changelog
vendored
@@ -1,8 +1,33 @@
|
||||
mongodb (1.6.2) unstable; urgency=low
|
||||
|
||||
* replica_sets some fixes
|
||||
* sharding some fixes with rs
|
||||
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10187
|
||||
|
||||
-- Richard Kreuter <richard@10gen.com> Wed, 1 Sep 2010 16:56:28 -0500
|
||||
|
||||
|
||||
mongodb (1.6.1) unstable; urgency=low
|
||||
|
||||
* replica_sets some fixes
|
||||
* sharding some fixes with rs
|
||||
* full change log http://jira.mongodb.org/browse/SERVER/fixforversion/10183
|
||||
|
||||
-- Richard Kreuter <richard@10gen.com> Tue, 17 Aug 2010 16:56:28 -0500
|
||||
|
||||
mongodb (1.6.0) unstable; urgency=low
|
||||
|
||||
* sharding stable
|
||||
* replica_sets stable
|
||||
|
||||
-- Richard Kreuter <richard@10gen.com> Thu, 05 Aug 2010 16:56:28 -0500
|
||||
|
||||
mongodb (1.5.8) unstable; urgency=low
|
||||
|
||||
* sharding lots of changes
|
||||
* replica_sets lots of changes
|
||||
|
||||
-- Richard Kreuter <richard@10gen.com> Tue, 03 Aug 2010 16:56:28 -0500
|
||||
|
||||
mongodb (1.5.7) unstable; urgency=low
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = MongoDB
|
||||
PROJECT_NUMBER = 1.5.8
|
||||
PROJECT_NUMBER = 1.6.2
|
||||
OUTPUT_DIRECTORY = docs/doxygen
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
t = db.getCollection( "foo" );
|
||||
t = db.getCollection( "foo_basic3" );
|
||||
|
||||
t.find( { "a.b" : 1 } ).toArray();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
t = db.getCollection( "foo" );
|
||||
t = db.getCollection( "foo_basic9" );
|
||||
|
||||
t.save( { "foo$bar" : 5 } );
|
||||
|
||||
|
||||
@@ -21,4 +21,10 @@ assert( res.databases && res.databases.length > 0 , "listDatabases 1 " + tojson(
|
||||
x = db._adminCommand( "ismaster" );
|
||||
assert( x.ismaster , "ismaster failed: " + tojson( x ) )
|
||||
|
||||
before = db.runCommand( "serverStatus" )
|
||||
sleep( 5000 )
|
||||
after = db.runCommand( "serverStatus" )
|
||||
assert.lt( 3 , after.uptimeEstimate , "up1" )
|
||||
assert.gt( after.uptimeEstimate , before.uptimeEstimate , "up2" )
|
||||
|
||||
// TODO: add more tests here
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
a = db.getSisterDB( "test_dbnamea" )
|
||||
b = db.getSisterDB( "test_dbnameA" )
|
||||
a = db.getSisterDB( "dbcasetest_dbnamea" )
|
||||
b = db.getSisterDB( "dbcasetest_dbnameA" )
|
||||
|
||||
a.dropDatabase();
|
||||
b.dropDatabase();
|
||||
|
||||
31
jstests/delx.js
Normal file
31
jstests/delx.js
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
a = db.getSisterDB("delxa" )
|
||||
b = db.getSisterDB("delxb" )
|
||||
|
||||
function setup( mydb ){
|
||||
mydb.dropDatabase();
|
||||
for ( i=0; i<100; i++ ){
|
||||
mydb.foo.insert( { _id : i } );
|
||||
}
|
||||
mydb.getLastError();
|
||||
}
|
||||
|
||||
setup( a );
|
||||
setup( b );
|
||||
|
||||
assert.eq( 100 , a.foo.find().itcount() , "A1" )
|
||||
assert.eq( 100 , b.foo.find().itcount() , "A2" )
|
||||
|
||||
x = a.foo.find().sort( { _id : 1 } ).batchSize( 60 )
|
||||
y = b.foo.find().sort( { _id : 1 } ).batchSize( 60 )
|
||||
|
||||
x.next();
|
||||
y.next();
|
||||
|
||||
a.foo.remove( { _id : { $gt : 50 } } );
|
||||
|
||||
assert.eq( 51 , a.foo.find().itcount() , "B1" )
|
||||
assert.eq( 100 , b.foo.find().itcount() , "B2" )
|
||||
|
||||
assert.eq( 59 , x.itcount() , "C1" )
|
||||
assert.eq( 99 , y.itcount() , "C2" ); // this was asserting because ClientCursor byLoc doesn't take db into consideration
|
||||
@@ -141,6 +141,14 @@ assert.soon( function(){ return am.lotOfIndexes.getIndexes().length == as.lotOfI
|
||||
|
||||
assert.eq( am.lotOfIndexes.getIndexes().length , as.lotOfIndexes.getIndexes().length , "lots of indexes b" )
|
||||
|
||||
// multi-update with $inc
|
||||
|
||||
am.mu1.update( { _id : 1 , $atomic : 1 } , { $inc : { x : 1 } } , true , true )
|
||||
x = { _id : 1 , x : 1 }
|
||||
assert.eq( x , am.mu1.findOne() , "mu1" );
|
||||
assert.soon( function(){ z = as.mu1.findOne(); printjson( z ); return friendlyEqual( x , z ); } , "mu2" )
|
||||
|
||||
|
||||
|
||||
rt.stop();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ doTest = function( signal ) {
|
||||
var master = replTest.getMaster();
|
||||
var config = master.getDB("local").system.replset.findOne();
|
||||
|
||||
replTest.stopSet( signal );
|
||||
replTest.stopSet( signal , true );
|
||||
|
||||
replTest.restart(0);
|
||||
replTest.restart(1);
|
||||
|
||||
52
jstests/sharding/addshard2.js
Normal file
52
jstests/sharding/addshard2.js
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
// don't start any shards, yet
|
||||
s = new ShardingTest( "add_shard2", 1, 0, 1, {useHostname : true} );
|
||||
|
||||
var conn1 = startMongodTest( 30001 , "add_shard21" , 0 , {useHostname : true} );
|
||||
var conn2 = startMongodTest( 30002 , "add_shard22" , 0 , {useHostname : true} );
|
||||
|
||||
var rs1 = new ReplSetTest( { "name" : "add_shard2_rs1", nodes : 3 , startPort : 31200 } );
|
||||
rs1.startSet();
|
||||
rs1.initiate();
|
||||
var master1 = rs1.getMaster();
|
||||
|
||||
var rs2 = new ReplSetTest( { "name" : "add_shard2_rs2", nodes : 3 , startPort : 31203 } );
|
||||
rs2.startSet();
|
||||
rs2.initiate();
|
||||
var master2 = rs2.getMaster();
|
||||
|
||||
// step 1. name given
|
||||
assert(s.admin.runCommand({"addshard" : getHostName()+":30001", "name" : "bar"}).ok, "failed to add shard in step 1");
|
||||
var shard = s.getDB("config").shards.findOne({"_id" : {"$nin" : ["shard0000"]}});
|
||||
assert(shard, "shard wasn't found");
|
||||
assert.eq("bar", shard._id, "shard has incorrect name");
|
||||
|
||||
// step 2. replica set
|
||||
assert(s.admin.runCommand({"addshard" : "add_shard2_rs1/"+getHostName()+":31200"}).ok, "failed to add shard in step 2");
|
||||
shard = s.getDB("config").shards.findOne({"_id" : {"$nin" : ["shard0000", "bar"]}});
|
||||
assert(shard, "shard wasn't found");
|
||||
assert.eq("add_shard2_rs1", shard._id, "t2 name");
|
||||
|
||||
// step 3. replica set w/ name given
|
||||
assert(s.admin.runCommand({"addshard" : "add_shard2_rs2/"+getHostName()+":31203", "name" : "myshard"}).ok,
|
||||
"failed to add shard in step 4");
|
||||
shard = s.getDB("config").shards.findOne({"_id" : {"$nin" : ["shard0000", "bar", "add_shard2_rs1"]}});
|
||||
assert(shard, "shard wasn't found");
|
||||
assert.eq("myshard", shard._id, "t3 name");
|
||||
|
||||
// step 4. no name given
|
||||
assert(s.admin.runCommand({"addshard" : getHostName()+":30002"}).ok, "failed to add shard in step 4");
|
||||
shard = s.getDB("config").shards.findOne({"_id" : {"$nin" : ["shard0000", "bar", "add_shard2_rs1", "myshard"]}});
|
||||
assert(shard, "shard wasn't found");
|
||||
assert.eq("shard0001", shard._id, "t4 name");
|
||||
|
||||
assert.eq(s.getDB("config").shards.count(), 5, "unexpected number of shards");
|
||||
|
||||
// step 5. replica set w/ a wrong host
|
||||
assert(!s.admin.runCommand({"addshard" : "add_shard2_rs2/NonExistingHost:31203"}).ok, "accepted bad hostname in step 5");
|
||||
|
||||
// step 6. replica set w/ mixed wrong/right hosts
|
||||
assert(!s.admin.runCommand({"addshard" : "add_shard2_rs2/"+getHostName()+":31203,foo:9999"}).ok,
|
||||
"accepted bad hostname in step 6");
|
||||
|
||||
s.stop();
|
||||
@@ -6,8 +6,14 @@ s.adminCommand( { shardcollection : "test.data" , key : { num : 1 } } );
|
||||
|
||||
db = s.getDB( "test" );
|
||||
|
||||
for ( i=0; i<100; i++ ){
|
||||
db.data.insert( { _id : i , num : i } );
|
||||
N = 100
|
||||
|
||||
forward = []
|
||||
backward = []
|
||||
for ( i=0; i<N; i++ ){
|
||||
db.data.insert( { _id : i , num : i , x : N - i } )
|
||||
forward.push( i )
|
||||
backward.push( ( N - 1 ) - i )
|
||||
}
|
||||
db.getLastError();
|
||||
|
||||
@@ -23,7 +29,7 @@ assert.eq( temp[0].shard , temp[2].shard , "A2" );
|
||||
assert.neq( temp[0].shard , temp[1].shard , "A3" );
|
||||
|
||||
temp = db.data.find().sort( { num : 1 } ).toArray();
|
||||
assert.eq( 100 , temp.length , "B1" );
|
||||
assert.eq( N , temp.length , "B1" );
|
||||
for ( i=0; i<100; i++ ){
|
||||
assert.eq( i , temp[i].num , "B2" )
|
||||
}
|
||||
@@ -39,6 +45,37 @@ assert.eq( 67 , z.length , "C2" )
|
||||
|
||||
print( "a: " + a + " b:" + b + " mongos slow down: " + Math.ceil( 100 * ( ( a - b ) / b ) ) + "%" )
|
||||
|
||||
//assert.lt( a , b * 1.3 , "C3 - speed test" );
|
||||
// -- secondary index sorting
|
||||
|
||||
function getSorted( by , want , dir , proj ){
|
||||
var s = {}
|
||||
s[by] = dir || 1;
|
||||
printjson( s )
|
||||
var cur = db.data.find( {} , proj || {} ).sort( s )
|
||||
return terse( cur.map( function(z){ return z[want]; } ) );
|
||||
}
|
||||
|
||||
function terse( a ){
|
||||
var s = "";
|
||||
for ( var i=0; i<a.length; i++ ){
|
||||
if ( i > 0 )
|
||||
s += ",";
|
||||
s += a[i];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
forward = terse(forward);
|
||||
backward = terse(backward);
|
||||
|
||||
assert.eq( forward , getSorted( "num" , "num" , 1 ) , "D1" )
|
||||
assert.eq( backward , getSorted( "num" , "num" , -1 ) , "D2" )
|
||||
|
||||
assert.eq( backward , getSorted( "x" , "num" , 1 ) , "D3" )
|
||||
assert.eq( forward , getSorted( "x" , "num" , -1 ) , "D4" )
|
||||
|
||||
assert.eq( backward , getSorted( "x" , "num" , 1 , { num : 1 } ) , "D5" )
|
||||
assert.eq( forward , getSorted( "x" , "num" , -1 , { num : 1 } ) , "D6" )
|
||||
|
||||
|
||||
s.stop();
|
||||
|
||||
@@ -25,4 +25,10 @@ assert( t.findOne( { i : i - 1 } ), "E" );
|
||||
t.remove( { i : i - 1 } );
|
||||
assert( db.getLastError().indexOf( "capped" ) >= 0, "F" );
|
||||
|
||||
assert( t.validate().valid, "G" );
|
||||
assert( t.validate().valid, "G" );
|
||||
|
||||
/* there is a cursor open here, so this is a convenient place for a quick cursor test. */
|
||||
|
||||
db._adminCommand("closeAllDatabases");
|
||||
|
||||
//assert( db.serverStatus().cursors.totalOpen == 0, "cursors open and shouldn't be");
|
||||
@@ -15,7 +15,7 @@ while ( bigString.length < 10000 )
|
||||
inserted = 0;
|
||||
num = 0;
|
||||
while ( inserted < ( 20 * 1024 * 1024 ) ){
|
||||
db.foo.insert( { _id : num++ , s : bigString } );
|
||||
db.foo.insert( { _id : num++ , s : bigString , x : Math.random() } );
|
||||
inserted += bigString.length;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ assert.soon( function(){
|
||||
return d < 5;
|
||||
} , "balance didn't happen" , 1000 * 60 * 3 , 5000 );
|
||||
|
||||
s.config.settings.update( { _id: "balancer" }, { $set : { stopped: true } } , true );
|
||||
|
||||
for ( i=0; i<s._rs.length; i++ ){
|
||||
r = s._rs[i];
|
||||
@@ -58,4 +59,14 @@ for ( i=0; i<s._rs.length; i++ ){
|
||||
assert.eq( x.master.md5 , x.slaves[j].md5 , "hashes same for: " + r.url + " slave: " + j );
|
||||
}
|
||||
|
||||
|
||||
assert.eq( num , db.foo.find().count() , "C1" )
|
||||
assert.eq( num , db.foo.find().itcount() , "C2" )
|
||||
assert.eq( num , db.foo.find().sort( { _id : 1 } ).itcount() , "C3" )
|
||||
assert.eq( num , db.foo.find().sort( { _id : -1 } ).itcount() , "C4" )
|
||||
db.foo.ensureIndex( { x : 1 } )
|
||||
assert.eq( num , db.foo.find().sort( { x : 1 } ).itcount() , "C5" )
|
||||
assert.eq( num , db.foo.find().sort( { x : -1 } ).itcount() , "C6" )
|
||||
|
||||
|
||||
s.stop()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Name: mongo
|
||||
Version: 1.5.8
|
||||
Version: 1.6.2
|
||||
Release: mongodb_1%{?dist}
|
||||
Summary: mongo client shell and tools
|
||||
License: AGPL 3.0
|
||||
@@ -130,11 +130,6 @@ fi
|
||||
%attr(0755,mongod,mongod) %dir /var/log/mongo
|
||||
%attr(0640,mongod,mongod) %config(noreplace) %verify(not md5 size mtime) /var/log/mongo/mongod.log
|
||||
|
||||
%files devel
|
||||
/usr/include/mongo
|
||||
%{_libdir}/libmongoclient.a
|
||||
#%{_libdir}/libmongotestfiles.a
|
||||
|
||||
%changelog
|
||||
* Thu Jan 28 2010 Richard M Kreuter <richard@10gen.com>
|
||||
- Minor fixes.
|
||||
|
||||
16
s/chunk.cpp
16
s/chunk.cpp
@@ -265,7 +265,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
// Save the new key boundaries in the configDB.
|
||||
_manager->save();
|
||||
_manager->save( false );
|
||||
|
||||
// Log all these changes in the configDB's log. We log a simple split differently than a multi-split.
|
||||
if ( newChunks.size() == 1) {
|
||||
@@ -584,7 +584,7 @@ namespace mongo {
|
||||
|
||||
_shards.insert(c->getShard());
|
||||
|
||||
save_inlock();
|
||||
save_inlock( true );
|
||||
log() << "no chunks for:" << ns << " so creating first: " << c->toString() << endl;
|
||||
}
|
||||
}
|
||||
@@ -880,16 +880,18 @@ namespace mongo {
|
||||
configServer.logChange( "dropCollection" , _ns , BSONObj() );
|
||||
}
|
||||
|
||||
void ChunkManager::save(){
|
||||
void ChunkManager::save( bool major ){
|
||||
rwlock lk( _lock , true );
|
||||
save_inlock();
|
||||
save_inlock( major );
|
||||
}
|
||||
|
||||
void ChunkManager::save_inlock(){
|
||||
void ChunkManager::save_inlock( bool major ){
|
||||
|
||||
ShardChunkVersion a = getVersion_inlock();
|
||||
assert( a > 0 || _chunkMap.size() <= 1 );
|
||||
ShardChunkVersion nextChunkVersion = a.incMajor();
|
||||
ShardChunkVersion nextChunkVersion = a;
|
||||
nextChunkVersion.inc( major );
|
||||
|
||||
vector<ChunkPtr> toFix;
|
||||
vector<ShardChunkVersion> newVersions;
|
||||
|
||||
@@ -907,7 +909,7 @@ namespace mongo {
|
||||
_sequenceNumber = ++NextSequenceNumber;
|
||||
|
||||
ShardChunkVersion myVersion = nextChunkVersion;
|
||||
++nextChunkVersion;
|
||||
nextChunkVersion.incMinor();
|
||||
toFix.push_back( c );
|
||||
newVersions.push_back( myVersion );
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ namespace mongo {
|
||||
void getAllShards( set<Shard>& all );
|
||||
void getShardsForRange(set<Shard>& shards, const BSONObj& min, const BSONObj& max); // [min, max)
|
||||
|
||||
void save();
|
||||
void save( bool major );
|
||||
|
||||
string toString() const;
|
||||
|
||||
@@ -307,7 +307,7 @@ namespace mongo {
|
||||
void _reload_inlock();
|
||||
void _load();
|
||||
|
||||
void save_inlock();
|
||||
void save_inlock( bool major );
|
||||
ShardChunkVersion getVersion_inlock() const;
|
||||
void ensureIndex_inlock();
|
||||
|
||||
|
||||
@@ -616,30 +616,44 @@ namespace mongo {
|
||||
help << "add a new shard to the system";
|
||||
}
|
||||
bool run(const string& , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){
|
||||
HostAndPort shardAddr( cmdObj.firstElement().valuestrsafe() );
|
||||
if ( shardAddr.isLocalHost() != grid.allowLocalHost() ){
|
||||
errmsg = "can't use localhost as a shard since all shards need to communicate. "
|
||||
"either use all shards and configdbs in localhost or all in actual IPs " ;
|
||||
log() << "addshard request " << cmdObj << " failed: attempt to mix localhosts and IPs" << endl;
|
||||
errmsg.clear();
|
||||
|
||||
// get replica set component hosts
|
||||
ConnectionString servers = ConnectionString::parse( cmdObj.firstElement().valuestrsafe() , errmsg );
|
||||
if ( ! errmsg.empty() ){
|
||||
log() << "addshard request " << cmdObj << " failed:" << errmsg << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// HostAndPort defaults to a different port; adjust if needed.
|
||||
if ( shardAddr.port() == CmdLine::DefaultDBPort ){
|
||||
shardAddr.setPort( CmdLine::ShardServerPort );
|
||||
// using localhost in server names implies every other process must use locahost addresses too
|
||||
vector<HostAndPort> serverAddrs = servers.getServers();
|
||||
for ( size_t i = 0 ; i < serverAddrs.size() ; i++ ){
|
||||
if ( serverAddrs[i].isLocalHost() != grid.allowLocalHost() ){
|
||||
errmsg = "can't use localhost as a shard since all shards need to communicate. "
|
||||
"either use all shards and configdbs in localhost or all in actual IPs " ;
|
||||
log() << "addshard request " << cmdObj << " failed: attempt to mix localhosts and IPs" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// it's fine if mongods of a set all use default port
|
||||
if ( ! serverAddrs[i].hasPort() ){
|
||||
serverAddrs[i].setPort( CmdLine::ShardServerPort );
|
||||
}
|
||||
}
|
||||
|
||||
// name is optional; addShard will provide one if needed
|
||||
string name = "";
|
||||
if ( cmdObj["name"].type() == String ) {
|
||||
name = cmdObj["name"].valuestrsafe();
|
||||
}
|
||||
|
||||
// maxSize is the space usage cap in a shard in MBs
|
||||
long long maxSize = 0;
|
||||
if ( cmdObj[ ShardFields::maxSize.name() ].isNumber() ){
|
||||
maxSize = cmdObj[ ShardFields::maxSize.name() ].numberLong();
|
||||
}
|
||||
|
||||
if ( ! grid.addShard( &name , shardAddr.toString() , maxSize , errmsg ) ){
|
||||
if ( ! grid.addShard( &name , servers , maxSize , errmsg ) ){
|
||||
log() << "addshard request " << cmdObj << " failed: " << errmsg << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -745,6 +745,7 @@ namespace mongo {
|
||||
fn == "reduce" ||
|
||||
fn == "query" ||
|
||||
fn == "sort" ||
|
||||
fn == "scope" ||
|
||||
fn == "verbose" ){
|
||||
b.append( e );
|
||||
}
|
||||
|
||||
@@ -653,7 +653,13 @@ namespace mongo {
|
||||
BSONObj msg = BSON( "_id" << id.str() << "server" << getHostNameCached() << "time" << DATENOW <<
|
||||
"what" << what << "ns" << ns << "details" << detail );
|
||||
log() << "config change: " << msg << endl;
|
||||
conn->insert( "config.changelog" , msg );
|
||||
|
||||
try {
|
||||
conn->insert( "config.changelog" , msg );
|
||||
}
|
||||
catch ( std::exception& e ){
|
||||
log() << "not logging config change: " << e.what() << endl;
|
||||
}
|
||||
|
||||
conn.done();
|
||||
}
|
||||
|
||||
@@ -528,7 +528,8 @@ namespace mongo {
|
||||
|
||||
log(0) << "_recvChunkStatus : " << res << endl;
|
||||
|
||||
if ( ! ok ){
|
||||
if ( ! ok || res["state"].String() == "fail" ){
|
||||
log( LL_ERROR ) << "_recvChunkStatus error : " << res << endl;
|
||||
errmsg = "_recvChunkStatus error";
|
||||
result.append( "cause" ,res );
|
||||
return false;
|
||||
@@ -544,7 +545,7 @@ namespace mongo {
|
||||
// 5.a
|
||||
migrateFromStatus._inCriticalSection = true;
|
||||
ShardChunkVersion myVersion = maxVersion;
|
||||
++myVersion;
|
||||
myVersion.incMajor();
|
||||
|
||||
{
|
||||
dblock lk;
|
||||
@@ -587,7 +588,8 @@ namespace mongo {
|
||||
if ( ! x.isEmpty() ){
|
||||
|
||||
BSONObjBuilder temp2;
|
||||
++myVersion;
|
||||
myVersion.incMinor();
|
||||
|
||||
temp2.appendTimestamp( "lastmod" , myVersion );
|
||||
|
||||
shardingState.setVersion( ns , myVersion );
|
||||
@@ -685,10 +687,12 @@ namespace mongo {
|
||||
catch ( std::exception& e ){
|
||||
state = FAIL;
|
||||
errmsg = e.what();
|
||||
log( LL_ERROR ) << "migrate failed: " << e.what() << endl;
|
||||
}
|
||||
catch ( ... ){
|
||||
state = FAIL;
|
||||
errmsg = "UNKNOWN ERROR";
|
||||
log( LL_ERROR ) << "migrate failed with unknown exception" << endl;
|
||||
}
|
||||
active = false;
|
||||
}
|
||||
@@ -739,7 +743,7 @@ namespace mongo {
|
||||
auto_ptr<DBClientCursor> cursor = conn->query( ns , Query().minKey( min ).maxKey( max ) , /* QueryOption_Exhaust */ 0 );
|
||||
assert( cursor.get() );
|
||||
while ( cursor->more() ){
|
||||
BSONObj o = cursor->next();
|
||||
BSONObj o = cursor->next().getOwned();
|
||||
{
|
||||
writelock lk( ns );
|
||||
Helpers::upsert( ns , o );
|
||||
@@ -756,7 +760,11 @@ namespace mongo {
|
||||
BSONObj res;
|
||||
if ( ! conn->runCommand( "admin" , BSON( "_transferMods" << 1 ) , res ) ){
|
||||
state = FAIL;
|
||||
errmsg = "_transferMods failed: ";
|
||||
errmsg += res.toString();
|
||||
log( LL_ERROR ) << "_transferMods failed: " << res << endl;
|
||||
conn.done();
|
||||
return;
|
||||
}
|
||||
if ( res["size"].number() == 0 )
|
||||
break;
|
||||
@@ -775,6 +783,7 @@ namespace mongo {
|
||||
log() << "_transferMods failed in STEADY state: " << res << endl;
|
||||
errmsg = res.toString();
|
||||
state = FAIL;
|
||||
conn.done();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -801,9 +810,10 @@ namespace mongo {
|
||||
b.append( "from" , from );
|
||||
b.append( "min" , min );
|
||||
b.append( "max" , max );
|
||||
|
||||
|
||||
b.append( "state" , stateString() );
|
||||
|
||||
if ( state == FAIL )
|
||||
b.append( "errmsg" , errmsg );
|
||||
{
|
||||
BSONObjBuilder bb( b.subobjStart( "counts" ) );
|
||||
bb.append( "cloned" , numCloned );
|
||||
|
||||
@@ -603,7 +603,8 @@ namespace mongo {
|
||||
BSONObj x = loc.obj().extractFields(_key);
|
||||
|
||||
MyMap::const_iterator a = _map.upper_bound( x );
|
||||
a--;
|
||||
if ( a != _map.begin() )
|
||||
a--;
|
||||
|
||||
bool good = x.woCompare( a->second.first ) >= 0 && x.woCompare( a->second.second ) < 0;
|
||||
#if 0
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace mongo {
|
||||
class WriteBackCommand : public Command {
|
||||
public:
|
||||
virtual LockType locktype() const { return NONE; }
|
||||
virtual bool slaveOk() const { return false; }
|
||||
virtual bool slaveOk() const { return true; }
|
||||
virtual bool adminOnly() const { return true; }
|
||||
|
||||
WriteBackCommand() : Command( "writebacklisten" ){}
|
||||
|
||||
102
s/grid.cpp
102
s/grid.cpp
@@ -115,41 +115,107 @@ namespace mongo {
|
||||
_allowLocalShard = allow;
|
||||
}
|
||||
|
||||
bool Grid::addShard( string* name , const string& host , long long maxSize , string& errMsg ){
|
||||
// name is optional
|
||||
bool Grid::addShard( string* name , const ConnectionString& servers , long long maxSize , string& errMsg ){
|
||||
// name can be NULL, so privide a dummy one here to avoid testing it elsewhere
|
||||
string nameInternal;
|
||||
if ( ! name ) {
|
||||
name = &nameInternal;
|
||||
}
|
||||
|
||||
// Check whether the host exists and is operative. In order to be accepted as a new shard, that
|
||||
// mongod must not have any database name that exists already in any other shards. If that
|
||||
// test passes, the new shard's databases are going to be entered as non-sharded db's whose
|
||||
// primary is the newly added shard.
|
||||
// Check whether the host (or set) exists and run several sanity checks on this request.
|
||||
// There are two set of sanity checks: making sure adding this particular shard is consistent
|
||||
// with the replica set state (if it exists) and making sure this shards databases can be
|
||||
// brought into the grid without conflict.
|
||||
|
||||
vector<string> dbNames;
|
||||
try {
|
||||
ScopedDbConnection newShardConn( host );
|
||||
ScopedDbConnection newShardConn( servers );
|
||||
newShardConn->getLastError();
|
||||
|
||||
if ( newShardConn->type() == ConnectionString::SYNC ){
|
||||
newShardConn.done();
|
||||
errMsg = "can't use sync cluster as a shard. for replica set, have to use <name>/<server1>,<server2>,...";
|
||||
errMsg = "can't use sync cluster as a shard. for replica set, have to use <setname>/<server1>,<server2>,...";
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the shard's local db's listing
|
||||
BSONObj res;
|
||||
bool ok = newShardConn->runCommand( "admin" , BSON( "listDatabases" << 1 ) , res );
|
||||
BSONObj resIsMaster;
|
||||
bool ok = newShardConn->runCommand( "admin" , BSON( "isMaster" << 1 ) , resIsMaster );
|
||||
if ( !ok ){
|
||||
ostringstream ss;
|
||||
ss << "failed listing " << host << " databases:" << res;
|
||||
ss << "failed running isMaster: " << resIsMaster;
|
||||
errMsg = ss.str();
|
||||
newShardConn.done();
|
||||
return false;
|
||||
}
|
||||
|
||||
BSONObjIterator i( res["databases"].Obj() );
|
||||
// if the shard has only one host, make sure it is not part of a replica set
|
||||
string setName = resIsMaster["setName"].str();
|
||||
string commandSetName = servers.getSetName();
|
||||
if ( commandSetName.empty() && ! setName.empty() ){
|
||||
ostringstream ss;
|
||||
ss << "host is part of set: " << setName << " use replica set url format <setname>/<server1>,<server2>,....";
|
||||
errMsg = ss.str();
|
||||
newShardConn.done();
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the shard is part of replica set, make sure it is the right one
|
||||
if ( ! commandSetName.empty() && ( commandSetName != setName ) ){
|
||||
ostringstream ss;
|
||||
ss << "host is part of a different set: " << setName;
|
||||
errMsg = ss.str();
|
||||
newShardConn.done();
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the shard is part of a replica set, make sure all the hosts mentioned in 'servers' are part of
|
||||
// the set. It is fine if not all members of the set are present in 'servers'.
|
||||
bool foundAll = true;
|
||||
string offendingHost;
|
||||
if ( ! commandSetName.empty() ){
|
||||
set<string> hostSet;
|
||||
BSONObjIterator iter( resIsMaster["hosts"].Obj() );
|
||||
while ( iter.more() ){
|
||||
hostSet.insert( iter.next().String() ); // host:port
|
||||
}
|
||||
|
||||
vector<HostAndPort> hosts = servers.getServers();
|
||||
for ( size_t i = 0 ; i < hosts.size() ; i++ ){
|
||||
string host = hosts[i].toString(); // host:port
|
||||
if ( hostSet.find( host ) == hostSet.end() ){
|
||||
offendingHost = host;
|
||||
foundAll = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ! foundAll ){
|
||||
ostringstream ss;
|
||||
ss << "host " << offendingHost << " does not belong to replica set " << setName;;
|
||||
errMsg = ss.str();
|
||||
newShardConn.done();
|
||||
return false;
|
||||
}
|
||||
|
||||
// shard name defaults to the name of the replica set
|
||||
if ( name->empty() && ! setName.empty() )
|
||||
*name = setName;
|
||||
|
||||
// In order to be accepted as a new shard, that mongod must not have any database name that exists already
|
||||
// in any other shards. If that test passes, the new shard's databases are going to be entered as
|
||||
// non-sharded db's whose primary is the newly added shard.
|
||||
|
||||
BSONObj resListDB;
|
||||
ok = newShardConn->runCommand( "admin" , BSON( "listDatabases" << 1 ) , resListDB );
|
||||
if ( !ok ){
|
||||
ostringstream ss;
|
||||
ss << "failed listing " << servers.toString() << "'s databases:" << resListDB;
|
||||
errMsg = ss.str();
|
||||
newShardConn.done();
|
||||
return false;
|
||||
}
|
||||
|
||||
BSONObjIterator i( resListDB["databases"].Obj() );
|
||||
while ( i.more() ){
|
||||
BSONObj dbEntry = i.next().Obj();
|
||||
const string& dbName = dbEntry["name"].String();
|
||||
@@ -176,7 +242,7 @@ namespace mongo {
|
||||
DBConfigPtr config = getDBConfig( *it , false );
|
||||
if ( config.get() != NULL ){
|
||||
ostringstream ss;
|
||||
ss << "trying to add shard " << host << " because local database " << *it;
|
||||
ss << "trying to add shard " << servers.toString() << " because local database " << *it;
|
||||
ss << " exists in another " << config->getPrimary().toString();
|
||||
errMsg = ss.str();
|
||||
return false;
|
||||
@@ -192,7 +258,7 @@ namespace mongo {
|
||||
// build the ConfigDB shard document
|
||||
BSONObjBuilder b;
|
||||
b.append( "_id" , *name );
|
||||
b.append( "host" , host );
|
||||
b.append( "host" , servers.toString() );
|
||||
if ( maxSize > 0 ){
|
||||
b.append( ShardFields::maxSize.name() , maxSize );
|
||||
}
|
||||
@@ -201,8 +267,8 @@ namespace mongo {
|
||||
{
|
||||
ScopedDbConnection conn( configServer.getPrimary() );
|
||||
|
||||
// check whether this host:port is not an already a known shard
|
||||
BSONObj old = conn->findOne( ShardNS::shard , BSON( "host" << host ) );
|
||||
// check whether the set of hosts (or single host) is not an already a known shard
|
||||
BSONObj old = conn->findOne( ShardNS::shard , BSON( "host" << servers.toString() ) );
|
||||
if ( ! old.isEmpty() ){
|
||||
errMsg = "host already used";
|
||||
conn.done();
|
||||
@@ -228,7 +294,7 @@ namespace mongo {
|
||||
for ( vector<string>::const_iterator it = dbNames.begin(); it != dbNames.end(); ++it ){
|
||||
DBConfigPtr config = getDBConfig( *it , true , *name );
|
||||
if ( ! config ){
|
||||
log() << "adding shard " << host << " even though could not add database " << *it << endl;
|
||||
log() << "adding shard " << servers << " even though could not add database " << *it << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
s/grid.h
7
s/grid.h
@@ -57,18 +57,17 @@ namespace mongo {
|
||||
/**
|
||||
*
|
||||
* addShard will create a new shard in the grid. It expects a mongod process to be runing
|
||||
* on the provided address.
|
||||
* TODO - add the mongod's databases to the grid
|
||||
* on the provided address. Adding a shard that is a replica set is supported.
|
||||
*
|
||||
* @param name is an optional string with the name of the shard. if ommited, grid will
|
||||
* generate one and update the parameter.
|
||||
* @param host is the complete address of the machine where the shard will be
|
||||
* @param servers is the connection string of the shard being added
|
||||
* @param maxSize is the optional space quota in bytes. Zeros means there's no limitation to
|
||||
* space usage
|
||||
* @param errMsg is the error description in case the operation failed.
|
||||
* @return true if shard was successfully added.
|
||||
*/
|
||||
bool addShard( string* name , const string& host , long long maxSize , string& errMsg );
|
||||
bool addShard( string* name , const ConnectionString& servers , long long maxSize , string& errMsg );
|
||||
|
||||
/**
|
||||
* @return true if the config database knows about a host 'name'
|
||||
|
||||
@@ -123,7 +123,8 @@ namespace mongo {
|
||||
log() << staleConfig.what() << " attempt: " << attempt << endl;
|
||||
uassert( 10195 , "too many attempts to update config, failing" , attempt < 5 );
|
||||
ShardConnection::checkMyConnectionVersions( getns() );
|
||||
sleepsecs( attempt );
|
||||
if (!staleConfig.justConnection() )
|
||||
sleepsecs( attempt );
|
||||
reset( ! staleConfig.justConnection() );
|
||||
_d.markReset();
|
||||
process( attempt + 1 );
|
||||
|
||||
@@ -63,10 +63,7 @@ namespace mongo {
|
||||
|
||||
class ShardingConnectionHook : public DBConnectionHook {
|
||||
public:
|
||||
virtual void onCreate( DBClientBase * conn ){
|
||||
if ( conn->type() != ConnectionString::SYNC )
|
||||
conn->simpleCommand( "admin" , 0 , "switchtoclienterrors" );
|
||||
}
|
||||
|
||||
virtual void onHandedOut( DBClientBase * conn ){
|
||||
ClientInfo::get()->addShard( conn->getServerAddress() );
|
||||
}
|
||||
@@ -92,10 +89,12 @@ namespace mongo {
|
||||
r.process();
|
||||
}
|
||||
catch ( DBException& e ){
|
||||
log() << "DBException in process: " << e.what() << endl;
|
||||
|
||||
le->raiseError( e.getCode() , e.what() );
|
||||
|
||||
m.header()->id = r.id();
|
||||
log() << "UserException: " << e.what() << endl;
|
||||
|
||||
if ( r.expectResponse() ){
|
||||
BSONObj err = BSON( "$err" << e.what() << "code" << e.getCode() );
|
||||
replyToQuery( ResultFlag_ErrSet, p , m , err );
|
||||
|
||||
13
s/shard.cpp
13
s/shard.cpp
@@ -76,6 +76,12 @@ namespace mongo {
|
||||
Shard s( name , host , maxSize , isDraining );
|
||||
_lookup[name] = s;
|
||||
_lookup[host] = s;
|
||||
|
||||
// add rs name to lookup (if it exists)
|
||||
size_t pos;
|
||||
if ((pos = host.find('/', 0)) != string::npos) {
|
||||
_lookup[host.substr(0, pos)] = s;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -90,6 +96,13 @@ namespace mongo {
|
||||
{
|
||||
scoped_lock lk( _mutex );
|
||||
map<string,Shard>::iterator i = _lookup.find( ident );
|
||||
|
||||
// if normal find didn't find anything, try to find by rs name
|
||||
size_t pos;
|
||||
if ( i == _lookup.end() && (pos = ident.find('/', 0)) != string::npos) {
|
||||
i = _lookup.find( ident.substr(0, pos) );
|
||||
}
|
||||
|
||||
if ( i != _lookup.end() )
|
||||
return i->second;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace mongo {
|
||||
|
||||
/**
|
||||
* holds all the actual db connections for a client to various servers
|
||||
* 1 pre thread, so don't have to worry about thread safety
|
||||
*/
|
||||
class ClientConnections : boost::noncopyable {
|
||||
public:
|
||||
@@ -70,7 +71,8 @@ namespace mongo {
|
||||
_hosts.clear();
|
||||
}
|
||||
|
||||
DBClientBase * get( const string& addr ){
|
||||
DBClientBase * get( const string& addr , const string& ns ){
|
||||
_check( ns );
|
||||
scoped_lock lk( _mutex );
|
||||
Status* &s = _hosts[addr];
|
||||
if ( ! s )
|
||||
@@ -152,9 +154,16 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
|
||||
void _check( const string& ns ){
|
||||
if ( ns.size() == 0 || _seenNS.count( ns ) )
|
||||
return;
|
||||
_seenNS.insert( ns );
|
||||
checkVersions( ns );
|
||||
}
|
||||
|
||||
map<string,Status*> _hosts;
|
||||
mongo::mutex _mutex;
|
||||
|
||||
set<string> _seenNS;
|
||||
// -----
|
||||
|
||||
static thread_specific_ptr<ClientConnections> _perThread;
|
||||
@@ -188,7 +197,7 @@ namespace mongo {
|
||||
|
||||
void ShardConnection::_init(){
|
||||
assert( _addr.size() );
|
||||
_conn = ClientConnections::get()->get( _addr );
|
||||
_conn = ClientConnections::get()->get( _addr , _ns );
|
||||
_finishedInit = false;
|
||||
}
|
||||
|
||||
|
||||
17
s/util.h
17
s/util.h
@@ -58,11 +58,19 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
|
||||
ShardChunkVersion incMajor() const {
|
||||
return ShardChunkVersion( _major + 1 , 0 );
|
||||
void inc( bool major ){
|
||||
if ( major )
|
||||
incMajor();
|
||||
else
|
||||
incMinor();
|
||||
}
|
||||
|
||||
void operator++(){
|
||||
void incMajor() {
|
||||
_major++;
|
||||
_minor = 0;
|
||||
}
|
||||
|
||||
void incMinor() {
|
||||
_minor++;
|
||||
}
|
||||
|
||||
@@ -79,8 +87,9 @@ namespace mongo {
|
||||
ss << _major << "|" << _minor;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
operator unsigned long long() const { return _combined; }
|
||||
|
||||
|
||||
ShardChunkVersion& operator=( const BSONElement& elem ){
|
||||
switch ( elem.type() ){
|
||||
case Timestamp:
|
||||
|
||||
@@ -156,7 +156,7 @@ namespace mongo {
|
||||
JSBool mongo_external_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
|
||||
Convertor c( cx );
|
||||
|
||||
uassert( 10238 , "0 or 1 args to Mongo" , argc <= 1 );
|
||||
smuassert( cx , "0 or 1 args to Mongo" , argc <= 1 );
|
||||
|
||||
string host = "127.0.0.1";
|
||||
if ( argc > 0 )
|
||||
@@ -207,9 +207,9 @@ namespace mongo {
|
||||
};
|
||||
|
||||
JSBool mongo_find(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){
|
||||
uassert( 10240 , "mongo_find neesd 6 args" , argc == 6 );
|
||||
smuassert( cx , "mongo_find needs 6 args" , argc == 6 );
|
||||
shared_ptr< DBClientWithCommands > * connHolder = (shared_ptr< DBClientWithCommands >*)JS_GetPrivate( cx , obj );
|
||||
uassert( 10241 , "no connection!" , connHolder && connHolder->get() );
|
||||
smuassert( cx , "no connection!" , connHolder && connHolder->get() );
|
||||
DBClientWithCommands *conn = connHolder->get();
|
||||
|
||||
Convertor c( cx );
|
||||
|
||||
@@ -243,6 +243,20 @@ DBQuery.prototype.explain = function (verbose) {
|
||||
if (!verbose) {
|
||||
delete e.allPlans;
|
||||
delete e.oldPlan;
|
||||
if (e.shards){
|
||||
for (var key in e.shards){
|
||||
var s = e.shards[key];
|
||||
if(s.length === undefined){
|
||||
delete s.allPlans;
|
||||
delete s.oldPlan;
|
||||
} else {
|
||||
for (var i=0; i < s.length; i++){
|
||||
delete s[i].allPlans;
|
||||
delete s[i].oldPlan;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -62,6 +62,13 @@ startMongodTest = function (port, dirname, restart, extraOptions ) {
|
||||
f = startMongodNoReset;
|
||||
if (!dirname)
|
||||
dirname = "" + port; // e.g., data/db/27000
|
||||
|
||||
var useHostname = false;
|
||||
if (extraOptions) {
|
||||
useHostname = extraOptions.useHostname;
|
||||
delete extraOptions.useHostname;
|
||||
}
|
||||
|
||||
|
||||
var options =
|
||||
{
|
||||
@@ -78,7 +85,7 @@ startMongodTest = function (port, dirname, restart, extraOptions ) {
|
||||
|
||||
var conn = f.apply(null, [ options ] );
|
||||
|
||||
conn.name = "localhost:" + port;
|
||||
conn.name = (useHostname ? getHostName() : "localhost") + ":" + port;
|
||||
return conn;
|
||||
}
|
||||
|
||||
@@ -145,6 +152,10 @@ myPort = function() {
|
||||
return 27017;
|
||||
}
|
||||
|
||||
/**
|
||||
* otherParams can be:
|
||||
* * useHostname to use the hostname (instead of localhost)
|
||||
*/
|
||||
ShardingTest = function( testName , numShards , verboseLevel , numMongos , otherParams ){
|
||||
this._testName = testName;
|
||||
|
||||
@@ -155,7 +166,10 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other
|
||||
if ( otherParams.sync && numShards < 3 )
|
||||
throw "if you want sync, you need at least 3 servers";
|
||||
|
||||
var localhost = "localhost";
|
||||
var localhost = otherParams.useHostname ? getHostName() : "localhost";
|
||||
|
||||
this._alldbpaths = []
|
||||
|
||||
|
||||
if ( otherParams.rs ){
|
||||
localhost = getHostName();
|
||||
@@ -165,6 +179,11 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other
|
||||
var rs = new ReplSetTest( { name : testName + "-rs" + i , nodes : 3 , startPort : 31100 + ( i * 100 ) } );
|
||||
this._rs[i] = { test : rs , nodes : rs.startSet( { oplogSize:40 } ) , url : rs.getURL() };
|
||||
rs.initiate();
|
||||
|
||||
}
|
||||
|
||||
for ( var i=0; i<numShards; i++){
|
||||
var rs = this._rs[i].test;
|
||||
rs.getMaster().getDB( "admin" ).foo.save( { x : 1 } )
|
||||
rs.awaitReplication();
|
||||
this._connections.push( new Mongo( rs.getURL() ) );
|
||||
@@ -173,6 +192,7 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other
|
||||
this._configServers = []
|
||||
for ( var i=0; i<3; i++ ){
|
||||
var conn = startMongodTest( 30000 + i , testName + "-config" + i );
|
||||
this._alldbpaths.push( testName + "-config" + i )
|
||||
this._configServers.push( conn );
|
||||
}
|
||||
|
||||
@@ -182,17 +202,18 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other
|
||||
}
|
||||
else {
|
||||
for ( var i=0; i<numShards; i++){
|
||||
var conn = startMongodTest( 30000 + i , testName + i );
|
||||
var conn = startMongodTest( 30000 + i , testName + i, 0, {useHostname : otherParams.useHostname} );
|
||||
this._alldbpaths.push( testName +i )
|
||||
this._connections.push( conn );
|
||||
}
|
||||
|
||||
if ( otherParams.sync ){
|
||||
this._configDB = "localhost:30000,localhost:30001,localhost:30002";
|
||||
this._configDB = localhost+":30000,"+localhost+":30001,"+localhost+":30002";
|
||||
this._configConnection = new Mongo( this._configDB );
|
||||
this._configConnection.getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );
|
||||
}
|
||||
else {
|
||||
this._configDB = "localhost:30000";
|
||||
this._configDB = localhost + ":30000";
|
||||
this._connections[0].getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );
|
||||
}
|
||||
}
|
||||
@@ -201,6 +222,7 @@ ShardingTest = function( testName , numShards , verboseLevel , numMongos , other
|
||||
var startMongosPort = 31000;
|
||||
for ( var i=0; i<(numMongos||1); i++ ){
|
||||
var myPort = startMongosPort - i;
|
||||
print("config: "+this._configDB);
|
||||
var conn = startMongos( { port : startMongosPort - i , v : verboseLevel || 0 , configdb : this._configDB } );
|
||||
conn.name = localhost + ":" + myPort;
|
||||
this._mongos.push( conn );
|
||||
@@ -316,6 +338,11 @@ ShardingTest.prototype.stop = function(){
|
||||
this._rs[i].test.stopSet( 15 );
|
||||
}
|
||||
}
|
||||
if ( this._alldbpaths ){
|
||||
for( i=0; i<this._alldbpaths.length; i++ ){
|
||||
resetDbpath( "/data/db/" + this._alldbpaths[i] );
|
||||
}
|
||||
}
|
||||
|
||||
print('*** ' + this._testName + " completed successfully ***");
|
||||
}
|
||||
@@ -966,6 +993,8 @@ ReplSetTest = function( opts ){
|
||||
this.name = opts.name || "testReplSet";
|
||||
this.host = opts.host || getHostName();
|
||||
this.numNodes = opts.nodes || 0;
|
||||
this.useSeedList = opts.useSeedList || false;
|
||||
|
||||
this.bridged = opts.bridged || false;
|
||||
this.ports = [];
|
||||
|
||||
@@ -1024,6 +1053,10 @@ ReplSetTest.prototype.getPort = function( n ){
|
||||
ReplSetTest.prototype.getPath = function( n ){
|
||||
var p = "/data/db/" + this.name + "-";
|
||||
p += n.toString();
|
||||
if ( ! this._alldbpaths )
|
||||
this._alldbpaths = [ p ];
|
||||
else
|
||||
this._alldbpaths.push( p );
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1326,9 +1359,15 @@ ReplSetTest.prototype.stop = function( n , signal ){
|
||||
return stopMongod( port , signal || 15 );
|
||||
}
|
||||
|
||||
ReplSetTest.prototype.stopSet = function( signal ) {
|
||||
ReplSetTest.prototype.stopSet = function( signal , forRestart ) {
|
||||
for(i=0; i < this.ports.length; i++) {
|
||||
this.stop( i, signal );
|
||||
}
|
||||
if ( ! forRestart && this._alldbpaths ){
|
||||
for( i=0; i<this._alldbpaths.length; i++ ){
|
||||
resetDbpath( this._alldbpaths[i] );
|
||||
}
|
||||
}
|
||||
|
||||
print('*** Shut down repl set - test worked ****' )
|
||||
}
|
||||
|
||||
@@ -65,8 +65,7 @@ namespace mongo {
|
||||
}
|
||||
|
||||
bool BackgroundJob::wait(int msMax, unsigned maxsleep) {
|
||||
assert( state != NotStarted );
|
||||
unsigned ms = 0;
|
||||
unsigned ms = 1;
|
||||
Date_t start = jsTime();
|
||||
while ( state != Done ) {
|
||||
sleepmillis(ms);
|
||||
@@ -84,7 +83,7 @@ namespace mongo {
|
||||
|
||||
/* wait for several jobs to finish. */
|
||||
void BackgroundJob::wait(list<BackgroundJob*>& L, unsigned maxsleep) {
|
||||
unsigned ms = 0;
|
||||
unsigned ms = 1;
|
||||
{
|
||||
x:
|
||||
sleepmillis(ms);
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace mongo {
|
||||
|
||||
typedef boost::function<void()> lam;
|
||||
|
||||
/** typical usage is: task::fork( serverPtr ); */
|
||||
/** typical usage is: task::fork( new Server("threadname") ); */
|
||||
class Server : public Task {
|
||||
public:
|
||||
/** send a message to the port */
|
||||
void send(lam);
|
||||
|
||||
Server(string name) : _name(name) { }
|
||||
Server(string name) : _name(name), rq(false) { }
|
||||
virtual ~Server() { }
|
||||
|
||||
/** send message but block until function completes */
|
||||
@@ -42,9 +42,8 @@ namespace mongo {
|
||||
void requeue() { rq = true; }
|
||||
|
||||
protected:
|
||||
/* this needn't be abstract; i left it that way for now so i remember
|
||||
to call Client::initThread() when using in mongo... */
|
||||
virtual void starting() = 0;
|
||||
/* REMINDER : for use in mongod, you will want to have this call Client::initThread(). */
|
||||
virtual void starting() { }
|
||||
|
||||
private:
|
||||
virtual bool initClient() { return true; }
|
||||
|
||||
@@ -117,7 +117,6 @@ namespace mongo {
|
||||
|
||||
void Server::doWork() {
|
||||
starting();
|
||||
rq = false;
|
||||
while( 1 ) {
|
||||
lam f;
|
||||
try {
|
||||
@@ -134,7 +133,10 @@ namespace mongo {
|
||||
f();
|
||||
if( rq ) {
|
||||
rq = false;
|
||||
send(f);
|
||||
{
|
||||
boost::mutex::scoped_lock lk(m);
|
||||
d.push_back(f);
|
||||
}
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
log() << "Server::doWork() exception " << e.what() << endl;
|
||||
@@ -143,6 +145,27 @@ namespace mongo {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Server *s;
|
||||
static void abc(int i) {
|
||||
cout << "Hello " << i << endl;
|
||||
s->requeue();
|
||||
}
|
||||
class TaskUnitTest : public mongo::UnitTest {
|
||||
public:
|
||||
virtual void run() {
|
||||
lam f = boost::bind(abc, 3);
|
||||
//f();
|
||||
|
||||
s = new Server("unittest");
|
||||
fork(s);
|
||||
s->send(f);
|
||||
|
||||
sleepsecs(30);
|
||||
cout <<" done" << endl;
|
||||
|
||||
}
|
||||
}; // not running. taskunittest;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace mongo {
|
||||
string host() const { return _host; }
|
||||
|
||||
int port() const { return _port >= 0 ? _port : CmdLine::DefaultDBPort; }
|
||||
bool hasPort() const { return _port >= 0; }
|
||||
void setPort( int port ) { _port = port; }
|
||||
|
||||
private:
|
||||
|
||||
122
util/log.h
122
util/log.h
@@ -158,15 +158,7 @@ namespace mongo {
|
||||
static vector<Tee*> * globalTees;
|
||||
public:
|
||||
|
||||
static void logLockless( const StringData& s ){
|
||||
if ( doneSetup == 1717 ){
|
||||
fwrite( s.data() , s.size() , 1 , logfile );
|
||||
fflush( logfile );
|
||||
}
|
||||
else {
|
||||
cout << s.data() << endl;
|
||||
}
|
||||
}
|
||||
inline static void logLockless( const StringData& s );
|
||||
|
||||
static void setLogFile(FILE* f){
|
||||
scoped_lock lk(mutex);
|
||||
@@ -177,52 +169,9 @@ namespace mongo {
|
||||
return 1717;
|
||||
}
|
||||
|
||||
void flush(Tee *t = 0) {
|
||||
// this ensures things are sane
|
||||
if ( doneSetup == 1717 ) {
|
||||
string msg = ss.str();
|
||||
string threadName = getThreadName();
|
||||
const char * type = logLevelToString(logLevel);
|
||||
|
||||
int spaceNeeded = msg.size() + 64 + threadName.size();
|
||||
int bufSize = 128;
|
||||
while ( bufSize < spaceNeeded )
|
||||
bufSize += 128;
|
||||
|
||||
BufBuilder b(bufSize);
|
||||
time_t_to_String( time(0) , b.grow(20) );
|
||||
if (!threadName.empty()){
|
||||
b.appendChar( '[' );
|
||||
b.appendStr( threadName , false );
|
||||
b.appendChar( ']' );
|
||||
b.appendChar( ' ' );
|
||||
}
|
||||
if ( type[0] ){
|
||||
b.appendStr( type , false );
|
||||
b.appendStr( ": " , false );
|
||||
}
|
||||
b.appendStr( msg );
|
||||
|
||||
string out( b.buf() , b.len() - 1);
|
||||
|
||||
scoped_lock lk(mutex);
|
||||
|
||||
if( t ) t->write(logLevel,out);
|
||||
if ( globalTees ){
|
||||
for ( unsigned i=0; i<globalTees->size(); i++ )
|
||||
(*globalTees)[i]->write(logLevel,out);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
//syslog( LOG_INFO , "%s" , cc );
|
||||
#endif
|
||||
fwrite(out.data(), out.size(), 1, logfile);
|
||||
fflush(logfile);
|
||||
}
|
||||
_init();
|
||||
}
|
||||
inline void flush(Tee *t = 0);
|
||||
|
||||
Nullstream& setLogLevel(LogLevel l){
|
||||
inline Nullstream& setLogLevel(LogLevel l){
|
||||
logLevel = l;
|
||||
return *this;
|
||||
}
|
||||
@@ -416,6 +365,69 @@ namespace mongo {
|
||||
/** output the error # and error message with prefix.
|
||||
handy for use as parm in uassert/massert.
|
||||
*/
|
||||
string errnoWithPrefix( const char * prefix = 0 );
|
||||
string errnoWithPrefix( const char * prefix );
|
||||
|
||||
void Logstream::logLockless( const StringData& s ){
|
||||
if ( doneSetup == 1717 ){
|
||||
if(fwrite(s.data(), s.size(), 1, logfile)){
|
||||
fflush(logfile);
|
||||
}else{
|
||||
int x = errno;
|
||||
cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout << s.data() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Logstream::flush(Tee *t) {
|
||||
// this ensures things are sane
|
||||
if ( doneSetup == 1717 ) {
|
||||
string msg = ss.str();
|
||||
string threadName = getThreadName();
|
||||
const char * type = logLevelToString(logLevel);
|
||||
|
||||
int spaceNeeded = msg.size() + 64 + threadName.size();
|
||||
int bufSize = 128;
|
||||
while ( bufSize < spaceNeeded )
|
||||
bufSize += 128;
|
||||
|
||||
BufBuilder b(bufSize);
|
||||
time_t_to_String( time(0) , b.grow(20) );
|
||||
if (!threadName.empty()){
|
||||
b.appendChar( '[' );
|
||||
b.appendStr( threadName , false );
|
||||
b.appendChar( ']' );
|
||||
b.appendChar( ' ' );
|
||||
}
|
||||
if ( type[0] ){
|
||||
b.appendStr( type , false );
|
||||
b.appendStr( ": " , false );
|
||||
}
|
||||
b.appendStr( msg );
|
||||
|
||||
string out( b.buf() , b.len() - 1);
|
||||
|
||||
scoped_lock lk(mutex);
|
||||
|
||||
if( t ) t->write(logLevel,out);
|
||||
if ( globalTees ){
|
||||
for ( unsigned i=0; i<globalTees->size(); i++ )
|
||||
(*globalTees)[i]->write(logLevel,out);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
//syslog( LOG_INFO , "%s" , cc );
|
||||
#endif
|
||||
if(fwrite(out.data(), out.size(), 1, logfile)){
|
||||
fflush(logfile);
|
||||
}else{
|
||||
int x = errno;
|
||||
cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl;
|
||||
}
|
||||
}
|
||||
_init();
|
||||
}
|
||||
|
||||
} // namespace mongo
|
||||
|
||||
@@ -168,7 +168,11 @@ namespace mongo {
|
||||
const int ret = select(maxfd+1, fds, NULL, NULL, &maxSelectTime);
|
||||
|
||||
if (ret == 0){
|
||||
#if defined(__linux__)
|
||||
_elapsedTime += ( 10000 - maxSelectTime.tv_usec ) / 1000;
|
||||
#else
|
||||
_elapsedTime += 10;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
_elapsedTime += ret; // assume 1ms to grab connection. very rough
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace mongo {
|
||||
// mongo processes version support
|
||||
//
|
||||
|
||||
const char versionString[] = "1.5.9-pre-";
|
||||
const char versionString[] = "1.6.2";
|
||||
|
||||
string mongodVersion() {
|
||||
stringstream ss;
|
||||
|
||||
Reference in New Issue
Block a user