diff options
Diffstat (limited to 'tools/tool.cpp')
-rw-r--r-- | tools/tool.cpp | 218 |
1 files changed, 130 insertions, 88 deletions
diff --git a/tools/tool.cpp b/tools/tool.cpp index dbb3de1..f687269 100644 --- a/tools/tool.cpp +++ b/tools/tool.cpp @@ -35,31 +35,41 @@ namespace mongo { CmdLine cmdLine; - Tool::Tool( string name , bool localDBAllowed , string defaultDB , + Tool::Tool( string name , DBAccess access , string defaultDB , string defaultCollection , bool usesstdout ) : - _name( name ) , _db( defaultDB ) , _coll( defaultCollection ) , - _usesstdout(usesstdout), _noconnection(false), _autoreconnect(false), _conn(0), _paired(false) { - + _name( name ) , _db( defaultDB ) , _coll( defaultCollection ) , + _usesstdout(usesstdout), _noconnection(false), _autoreconnect(false), _conn(0), _slaveConn(0), _paired(false) { + _options = new po::options_description( "options" ); _options->add_options() - ("help","produce help message") - ("verbose,v", "be more verbose (include multiple times for more verbosity e.g. -vvvvv)") - ("host,h",po::value<string>(), "mongo host to connect to (\"left,right\" for pairs)" ) + ("help","produce help message") + ("verbose,v", "be more verbose (include multiple times for more verbosity e.g. -vvvvv)") + ; + + if ( access & REMOTE_SERVER ) + _options->add_options() + ("host,h",po::value<string>(), "mongo host to connect to ( <set name>/s1,s2 for sets)" ) ("port",po::value<string>(), "server port. Can also use --host hostname:port" ) - ("db,d",po::value<string>(), "database to use" ) - ("collection,c",po::value<string>(), "collection to use (some commands)" ) + ("ipv6", "enable IPv6 support (disabled by default)") + ("username,u",po::value<string>(), "username" ) ("password,p", new PasswordValue( &_password ), "password" ) - ("ipv6", "enable IPv6 support (disabled by default)") ; - if ( localDBAllowed ) + + if ( access & LOCAL_SERVER ) _options->add_options() - ("dbpath",po::value<string>(), "directly access mongod database " - "files in the given path, instead of connecting to a mongod " - "server - needs to lock the data directory, so cannot be " - "used if a mongod is currently accessing the same path" ) - ("directoryperdb", "if dbpath specified, each db is in a separate directory" ) - ; + ("dbpath",po::value<string>(), "directly access mongod database " + "files in the given path, instead of connecting to a mongod " + "server - needs to lock the data directory, so cannot be " + "used if a mongod is currently accessing the same path" ) + ("directoryperdb", "if dbpath specified, each db is in a separate directory" ) + ; + + if ( access & SPECIFY_DBCOL ) + _options->add_options() + ("db,d",po::value<string>(), "database to use" ) + ("collection,c",po::value<string>(), "collection to use (some commands)" ) + ; _hidden_options = new po::options_description( name + " hidden options" ); @@ -69,7 +79,7 @@ namespace mongo { } } - Tool::~Tool(){ + Tool::~Tool() { delete( _options ); delete( _hidden_options ); if ( _conn ) @@ -82,12 +92,20 @@ namespace mongo { printExtraHelpAfter(out); } - int Tool::main( int argc , char ** argv ){ + int Tool::main( int argc , char ** argv ) { static StaticObserver staticObserver; - + cmdLine.prealloc = false; - boost::filesystem::path::default_name_check( boost::filesystem::no_check ); + // The default value may vary depending on compile options, but for tools + // we want durability to be disabled. + cmdLine.dur = false; + +#if( BOOST_VERSION >= 104500 ) + boost::filesystem::path::default_name_check( boost::filesystem2::no_check ); +#else + boost::filesystem::path::default_name_check( boost::filesystem::no_check ); +#endif _name = argv[0]; @@ -106,23 +124,24 @@ namespace mongo { style(command_line_style).run() , _params ); po::notify( _params ); - } catch (po::error &e) { + } + catch (po::error &e) { cerr << "ERROR: " << e.what() << endl << endl; printHelp(cerr); return EXIT_BADOPTIONS; } // hide password from ps output - for (int i=0; i < (argc-1); ++i){ - if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--password")){ + for (int i=0; i < (argc-1); ++i) { + if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--password")) { char* arg = argv[i+1]; - while (*arg){ + while (*arg) { *arg++ = 'x'; } } } - if ( _params.count( "help" ) ){ + if ( _params.count( "help" ) ) { printHelp(cout); return 0; } @@ -136,11 +155,11 @@ namespace mongo { logLevel = s.length(); } } - + preSetup(); bool useDirectClient = hasParam( "dbpath" ); - + if ( ! useDirectClient ) { _host = "127.0.0.1"; if ( _params.count( "host" ) ) @@ -148,27 +167,28 @@ namespace mongo { if ( _params.count( "port" ) ) _host += ':' + _params["port"].as<string>(); - - if ( _noconnection ){ + + if ( _noconnection ) { // do nothing } else { string errmsg; ConnectionString cs = ConnectionString::parse( _host , errmsg ); - if ( ! cs.isValid() ){ + if ( ! cs.isValid() ) { cerr << "invalid hostname [" << _host << "] " << errmsg << endl; return -1; } - + _conn = cs.connect( errmsg ); - if ( ! _conn ){ + if ( ! _conn ) { cerr << "couldn't connect to [" << _host << "] " << errmsg << endl; return -1; } + + (_usesstdout ? cout : cerr ) << "connected to: " << _host << endl; } - - (_usesstdout ? cout : cerr ) << "connected to: " << _host << endl; + } else { if ( _params.count( "directoryperdb" ) ) { @@ -183,15 +203,15 @@ namespace mongo { try { acquirePathLock(); } - catch ( DBException& ){ + catch ( DBException& ) { cerr << endl << "If you are running a mongod on the same " - "path you should connect to that instead of direct data " - "file access" << endl << endl; + "path you should connect to that instead of direct data " + "file access" << endl << endl; dbexit( EXIT_CLEAN ); return -1; } - theFileAllocator().start(); + FileAllocator::get()->start(); } if ( _params.count( "db" ) ) @@ -204,7 +224,7 @@ namespace mongo { _username = _params["username"].as<string>(); if ( _params.count( "password" ) - && ( _password.empty() ) ) { + && ( _password.empty() ) ) { _password = askPassword(); } @@ -215,11 +235,11 @@ namespace mongo { try { ret = run(); } - catch ( DBException& e ){ + catch ( DBException& e ) { cerr << "assertion: " << e.toString() << endl; ret = -1; } - + if ( currentClient.get() ) currentClient->shutdown(); @@ -228,40 +248,60 @@ namespace mongo { return ret; } - DBClientBase& Tool::conn( bool slaveIfPaired ){ - // TODO: _paired is deprecated - if ( slaveIfPaired && _conn->type() == ConnectionString::SET ) - return ((DBClientReplicaSet*)_conn)->slaveConn(); + DBClientBase& Tool::conn( bool slaveIfPaired ) { + if ( slaveIfPaired && _conn->type() == ConnectionString::SET ) { + if (!_slaveConn) + _slaveConn = &((DBClientReplicaSet*)_conn)->slaveConn(); + return *_slaveConn; + } return *_conn; } - void Tool::addFieldOptions(){ + bool Tool::isMaster() { + if ( hasParam("dbpath") ) { + return true; + } + + BSONObj info; + bool isMaster; + bool ok = conn().isMaster(isMaster, &info); + + if (ok && !isMaster) { + cerr << "ERROR: trying to write to non-master " << conn().toString() << endl; + cerr << "isMaster info: " << info << endl; + return false; + } + + return true; + } + + void Tool::addFieldOptions() { add_options() - ("fields,f" , po::value<string>() , "comma separated list of field names e.g. -f name,age" ) - ("fieldFile" , po::value<string>() , "file with fields names - 1 per line" ) - ; + ("fields,f" , po::value<string>() , "comma separated list of field names e.g. -f name,age" ) + ("fieldFile" , po::value<string>() , "file with fields names - 1 per line" ) + ; } - void Tool::needFields(){ + void Tool::needFields() { - if ( hasParam( "fields" ) ){ + if ( hasParam( "fields" ) ) { BSONObjBuilder b; - + string fields_arg = getParam("fields"); pcrecpp::StringPiece input(fields_arg); - + string f; pcrecpp::RE re("([#\\w\\.\\s\\-]+),?" ); - while ( re.Consume( &input, &f ) ){ + while ( re.Consume( &input, &f ) ) { _fields.push_back( f ); b.append( f , 1 ); } - + _fieldsObj = b.obj(); return; } - if ( hasParam( "fieldFile" ) ){ + if ( hasParam( "fieldFile" ) ) { string fn = getParam( "fieldFile" ); if ( ! exists( fn ) ) throw UserException( 9999 , ((string)"file: " + fn ) + " doesn't exist" ); @@ -271,7 +311,7 @@ namespace mongo { ifstream file( fn.c_str() ); BSONObjBuilder b; - while ( file.rdstate() == ios_base::goodbit ){ + while ( file.rdstate() == ios_base::goodbit ) { file.getline( line , BUF_SIZE ); const char * cur = line; while ( isspace( cur[0] ) ) cur++; @@ -288,7 +328,7 @@ namespace mongo { throw UserException( 9998 , "you need to specify fields" ); } - void Tool::auth( string dbname ){ + void Tool::auth( string dbname ) { if ( ! dbname.size() ) dbname = _db; @@ -307,39 +347,39 @@ namespace mongo { throw UserException( 9997 , (string)"auth failed: " + errmsg ); } - BSONTool::BSONTool( const char * name , bool objcheck ) - : Tool( name , true , "" , "" ) , _objcheck( objcheck ){ - + BSONTool::BSONTool( const char * name, DBAccess access , bool objcheck ) + : Tool( name , access , "" , "" ) , _objcheck( objcheck ) { + add_options() - ("objcheck" , "validate object before inserting" ) - ("filter" , po::value<string>() , "filter to apply before inserting" ) - ; + ("objcheck" , "validate object before inserting" ) + ("filter" , po::value<string>() , "filter to apply before inserting" ) + ; } - int BSONTool::run(){ + int BSONTool::run() { _objcheck = hasParam( "objcheck" ); - + if ( hasParam( "filter" ) ) _matcher.reset( new Matcher( fromjson( getParam( "filter" ) ) ) ); - + return doRun(); } - long long BSONTool::processFile( const path& root ){ - string fileString = root.string(); - - long long fileLength = file_size( root ); + long long BSONTool::processFile( const path& root ) { + _fileName = root.string(); + + unsigned long long fileLength = file_size( root ); if ( fileLength == 0 ) { - out() << "file " << fileString << " empty, skipping" << endl; + out() << "file " << _fileName << " empty, skipping" << endl; return 0; } - FILE* file = fopen( fileString.c_str() , "rb" ); - if ( ! file ){ - log() << "error opening file: " << fileString << endl; + FILE* file = fopen( _fileName.c_str() , "rb" ); + if ( ! file ) { + log() << "error opening file: " << _fileName << endl; return 0; } @@ -349,11 +389,11 @@ namespace mongo { log(1) << "\t file size: " << fileLength << endl; - long long read = 0; - long long num = 0; - long long processed = 0; + unsigned long long read = 0; + unsigned long long num = 0; + unsigned long long processed = 0; - const int BUF_SIZE = 1024 * 1024 * 5; + const int BUF_SIZE = BSONObjMaxUserSize + ( 1024 * 1024 ); boost::scoped_array<char> buf_holder(new char[BUF_SIZE]); char * buf = buf_holder.get(); @@ -362,7 +402,7 @@ namespace mongo { while ( read < fileLength ) { int readlen = fread(buf, 4, 1, file); int size = ((int*)buf)[0]; - if ( size >= BUF_SIZE ){ + if ( size >= BUF_SIZE ) { cerr << "got an object of size: " << size << " terminating..." << endl; } uassert( 10264 , "invalid object size" , size < BUF_SIZE ); @@ -370,24 +410,24 @@ namespace mongo { readlen = fread(buf+4, size-4, 1, file); BSONObj o( buf ); - if ( _objcheck && ! o.valid() ){ + if ( _objcheck && ! o.valid() ) { cerr << "INVALID OBJECT - going try and pring out " << endl; cerr << "size: " << size << endl; BSONObjIterator i(o); - while ( i.more() ){ + while ( i.more() ) { BSONElement e = i.next(); try { e.validate(); } - catch ( ... ){ + catch ( ... ) { cerr << "\t\t NEXT ONE IS INVALID" << endl; } cerr << "\t name : " << e.fieldName() << " " << e.type() << endl; cerr << "\t " << e << endl; } } - - if ( _matcher.get() == 0 || _matcher->matches( o ) ){ + + if ( _matcher.get() == 0 || _matcher->matches( o ) ) { gotObject( o ); processed++; } @@ -398,14 +438,16 @@ namespace mongo { m.hit( o.objsize() ); } + fclose( file ); + uassert( 10265 , "counts don't match" , m.done() == fileLength ); out() << "\t " << m.hits() << " objects found" << endl; if ( _matcher.get() ) out() << "\t " << processed << " objects processed" << endl; return processed; } - - void setupSignals(){} + + void setupSignals( bool inFork ) {} } |