summaryrefslogtreecommitdiff
path: root/tools/tool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/tool.cpp')
-rw-r--r--tools/tool.cpp218
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 ) {}
}