Пример #1
0
Файл: log.cpp Проект: nunb/mongo
    void rotate() {
        if ( ! _enabled ) {
            cout << "LoggingManager not enabled" << endl;
            return;
        }

        if ( _file ) {
#ifdef _WIN32
            cout << "log rotation net yet supported on windows" << endl;
            return;
#else
            struct tm t;
            localtime_r( &_opened , &t );

            stringstream ss;
            ss << _path << "." << terseCurrentTime(false);
            string s = ss.str();
            rename( _path.c_str() , s.c_str() );
#endif
        }


        FILE* tmp = freopen(_path.c_str(), (_append ? "a" : "w"), stdout);
        if (!tmp) {
            cerr << "can't open: " << _path.c_str() << " for log file" << endl;
            dbexit( EXIT_BADOPTIONS );
            assert(0);
        }

        Logstream::setLogFile(tmp); // after this point no thread will be using old file

        _file = tmp;
        _opened = time(0);
    }
Пример #2
0
    void ConfigServer::logChange( const string& what , const string& ns , const BSONObj& detail ){
        assert( _primary.ok() );

        static bool createdCapped = false;
        static AtomicUInt num;
        
        ScopedDbConnection conn( _primary );
        
        if ( ! createdCapped ){
            try {
                conn->createCollection( "config.changelog" , 1024 * 1024 * 10 , true );
            }
            catch ( UserException& e ){
                log(1) << "couldn't create changelog (like race condition): " << e << endl;
                // don't care
            }
            createdCapped = true;
        }
     
        stringstream id;
        id << getHostNameCached() << "-" << terseCurrentTime() << "-" << num++;

        BSONObj msg = BSON( "_id" << id.str() << "server" << getHostNameCached() << "time" << DATENOW <<
                            "what" << what << "ns" << ns << "details" << detail );
        log() << "config change: " << msg << endl;

        try {
            conn->insert( "config.changelog" , msg );
        }
        catch ( std::exception& e ){
            log() << "not logging config change: " << e.what() << endl;                
        }
        
        conn.done();
    }
Пример #3
0
        void start( const string& lp , bool append ) {
            uassert( 10268 ,  "LoggingManager already started" , ! _enabled );
            _append = append;

            bool exists = boost::filesystem::exists(lp);
            bool isdir = boost::filesystem::is_directory(lp);
            bool isreg = boost::filesystem::is_regular(lp);

            if ( exists ) {
                if ( isdir ) {
                    cout << "logpath [" << lp << "] should be a filename, not a directory" << endl;
                    
                    dbexit( EXIT_BADOPTIONS );
                    assert( 0 );
                }

                if ( ! append ) {
                    // only attempt rename if log is regular file
                    if ( isreg ) {
                        stringstream ss;
                        ss << lp << "." << terseCurrentTime( false );
                        string s = ss.str();

                        if ( ! rename( lp.c_str() , s.c_str() ) ) {
                            cout << "log file [" << lp << "] exists; copied to temporary file [" << s << "]" << endl;
                        } else {
                            cout << "log file [" << lp << "] exists and couldn't make backup; run with --logappend or manually remove file (" << strerror(errno) << ")" << endl;
                            
                            dbexit( EXIT_BADOPTIONS );
                            assert( 0 );
                        }
                    }
                }
            }
            // test path
            FILE * test = fopen( lp.c_str() , _append ? "a" : "w" );
            if ( ! test ) {
                cout << "can't open [" << lp << "] for log file: " << errnoWithDescription() << endl;
                dbexit( EXIT_BADOPTIONS );
                assert( 0 );
            }

            if (append && exists){
                // two blank lines before and after
                const string msg = "\n\n***** SERVER RESTARTED *****\n\n\n";
                massert(14036, errnoWithPrefix("couldn't write to log file"),
                        fwrite(msg.data(), 1, msg.size(), test) == msg.size());
            }

            fclose( test );

            _path = lp;
            _enabled = 1;
            rotate();
        }
Пример #4
0
        void printDiff( BSONObj prev , BSONObj now ) { 
            if ( ! prev["totals"].isABSONObj() ||
                 ! now["totals"].isABSONObj() ) {
                cout << "." << endl;
                return;
            }

            prev = prev["totals"].Obj();
            now = now["totals"].Obj();
            
            vector<NSInfo> data;
            
            unsigned longest = 30;

            BSONObjIterator i( now );
            while ( i.more() ) {
                BSONElement e = i.next();
                
                // invalid, data fixed in 1.8.0
                if ( e.fieldName()[0] == '?' )
                    continue;
                
                if ( ! str::contains( e.fieldName() , '.' ) )
                    continue;
                
                BSONElement old = prev[e.fieldName()];
                if ( old.eoo() ) 
                    continue;
                
                if ( strlen( e.fieldName() ) > longest )
                    longest = strlen(e.fieldName());

                data.push_back( NSInfo( e.fieldName() , old.Obj() , e.Obj() ) );
            }
            
            std::sort( data.begin() , data.end() );

            cout << "\n"
                 << setw(longest) << "ns" 
                 << "\ttotal"  
                 << "\tread"    
                 << "\twrite"  
                 << "\t\t" << terseCurrentTime()
                 << endl;
            for ( int i=data.size()-1; i>=0 && data.size() - i < 10 ; i-- ) {
                cout << setw(longest) << data[i].ns 
                     << "\t" << setprecision(3) << data[i].diffTimeMS( "total" ) << "ms" 
                     << "\t" << setprecision(3) << data[i].diffTimeMS( "readLock" ) << "ms" 
                     << "\t" << setprecision(3) << data[i].diffTimeMS( "writeLock" ) << "ms" 
                     << endl;
            }
        }
Пример #5
0
        void rotate() {
            if ( ! _enabled ) {
                cout << "LoggingManager not enabled" << endl;
                return;
            }

            if ( _file ) {
#ifdef _WIN32
                cout << "log rotation net yet supported on windows" << endl;
                return;
#else
                struct tm t;
                localtime_r( &_opened , &t );

                stringstream ss;
                ss << _path << "." << terseCurrentTime(false);
                string s = ss.str();
                rename( _path.c_str() , s.c_str() );
#endif
            }


            FILE* tmp = freopen(_path.c_str(), (_append ? "a" : "w"), stdout);
            if (!tmp) {
                cerr << "can't open: " << _path.c_str() << " for log file" << endl;
                dbexit( EXIT_BADOPTIONS );
                assert(0);
            }

#ifdef _WIN32 // windows has these functions it just gives them a funny name
# define dup2 _dup2
# define fileno _fileno
#endif
            // redirect stderr to log file
            dup2(fileno(tmp), 2);

            Logstream::setLogFile(tmp); // after this point no thread will be using old file

#if 0 // enable to test redirection
            cout << "written to cout" << endl;
            cerr << "written to cerr" << endl;
            log() << "written to log()" << endl;
#endif

            _file = tmp;
            _opened = time(0);
        }
Пример #6
0
    RemoveSaver::RemoveSaver( const string& a , const string& b , const string& why) : _out(0) {
        static int NUM = 0;

        _root = dbpath;
        if ( a.size() )
            _root /= a;
        if ( b.size() )
            _root /= b;
        verify( a.size() || b.size() );

        _file = _root;

        stringstream ss;
        ss << why << "." << terseCurrentTime(false) << "." << NUM++ << ".bson";
        _file /= ss.str();

    }
Пример #7
0
    /* must never throw */
    void ConfigServer::logChange( const string& what , const string& ns , const BSONObj& detail ) {
        string changeID;

        try {
            // get this entry's ID so we can use on the exception code path too
            stringstream id;
            static AtomicUInt num;
            id << getHostNameCached() << "-" << terseCurrentTime() << "-" << num++;
            changeID = id.str();

            // send a copy of the message to the log in case it doesn't manage to reach config.changelog
            Client* c = currentClient.get();
            BSONObj msg = BSON( "_id" << changeID << "server" << getHostNameCached() << "clientAddr" << (c ? c->clientAddress(true) : "N/A")
                                << "time" << DATENOW << "what" << what << "ns" << ns << "details" << detail );
            log() << "about to log metadata event: " << msg << endl;

            assert( _primary.ok() );

            ScopedDbConnection conn( _primary );

            static bool createdCapped = false;
            if ( ! createdCapped ) {
                try {
                    conn->createCollection( "config.changelog" , 1024 * 1024 * 10 , true );
                }
                catch ( UserException& e ) {
                    log(1) << "couldn't create changelog (like race condition): " << e << endl;
                    // don't care
                }
                createdCapped = true;
            }

            conn->insert( "config.changelog" , msg );

            conn.done();

        }

        catch ( std::exception& e ) {
            // if we got here, it means the config change is only in the log; it didn't make it to config.changelog
            log() << "not logging config change: " << changeID << " " << e.what() << endl;
        }
    }
Пример #8
0
        void printDiff( const NamespaceStats& prev , const NamespaceStats& now ) {
            if ( prev.size() == 0 || now.size() == 0 ) {
                cout << "." << endl;
                return;
            }
            
            vector<NamespaceDiff> data = StatUtil::computeDiff( prev , now );
            
            unsigned longest = 30;
            
            for ( unsigned i=0; i < data.size(); i++ ) {
                const string& ns = data[i].ns;

                if ( ! useLocks() && ns.find( '.' ) == string::npos )
                    continue;

                if ( ns.size() > longest )
                    longest = ns.size();
            }
            
            int numberWidth = 10;

            cout << "\n"
                 << setw(longest) << ( useLocks() ? "db" : "ns" )
                 << setw(numberWidth+2) << "total"
                 << setw(numberWidth+2) << "read"
                 << setw(numberWidth+2) << "write"
                 << "\t\t" << terseCurrentTime()
                 << endl;
            for ( int i=data.size()-1; i>=0 && data.size() - i < 10 ; i-- ) {
                
                if ( ! useLocks() && data[i].ns.find( '.' ) == string::npos )
                    continue;

                cout << setw(longest) << data[i].ns 
                     << setw(numberWidth) << setprecision(3) << data[i].total() << "ms"
                     << setw(numberWidth) << setprecision(3) << data[i].read << "ms"
                     << setw(numberWidth) << setprecision(3) << data[i].write << "ms"
                     << endl;
            }

        }
Пример #9
0
    void ConfigServer::logChange( const string& what , const string& ns , const BSONObj& detail ){
        static bool createdCapped = false;
        static AtomicUInt num;
        
        ScopedDbConnection conn( _primary );
        
        if ( ! createdCapped ){
            conn->createCollection( "config.changelog" , 1024 * 1024 * 10 , true );
            createdCapped = true;
        }
     
        stringstream id;
        id << ourHostname << "-" << terseCurrentTime() << "-" << num++;

        conn->insert( "config.changelog" , BSON( "_id" << id.str() << 
                                                 "server" << ourHostname <<
                                                 "time" << DATENOW <<
                                                 "what" << what <<
                                                 "ns" << ns << 
                                                 "details" << detail ) );
        conn.done();
    }
Пример #10
0
        bool rotate() {
            if ( ! _enabled ) {
                cout << "LoggingManager not enabled" << endl;
                return true;
            }

            if ( _file ) {

#ifdef POSIX_FADV_DONTNEED
                posix_fadvise(fileno(_file), 0, 0, POSIX_FADV_DONTNEED);
#endif

                // Rename the (open) existing log file to a timestamped name
                stringstream ss;
                ss << _path << "." << terseCurrentTime( false );
                string s = ss.str();
                if (0 != rename(_path.c_str(), s.c_str())) {
                    error() << "Failed to rename " << _path << " to " << s;
                    return false;
                }
            }

            FILE* tmp = 0;  // The new file using the original logpath name

#if _WIN32
            // We rename an open log file (above, on next rotation) and the trick to getting Windows to do that is
            // to open the file with FILE_SHARE_DELETE.  So, we can't use the freopen() call that non-Windows
            // versions use because it would open the file without the FILE_SHARE_DELETE flag we need.
            //
            HANDLE newFileHandle = CreateFileA(
                    _path.c_str(),
                    GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    NULL,
                    OPEN_ALWAYS,
                    FILE_ATTRIBUTE_NORMAL,
                    NULL
            );
            if ( INVALID_HANDLE_VALUE != newFileHandle ) {
                int newFileDescriptor = _open_osfhandle( reinterpret_cast<intptr_t>(newFileHandle), _O_APPEND );
                tmp = _fdopen( newFileDescriptor, _append ? "a" : "w" );
            }
#else
            tmp = freopen(_path.c_str(), _append ? "a" : "w", stdout);
#endif
            if ( !tmp ) {
                cerr << "can't open: " << _path.c_str() << " for log file" << endl;
                return false;
            }

            // redirect stdout and stderr to log file
            dup2( fileno( tmp ), 1 );   // stdout
            dup2( fileno( tmp ), 2 );   // stderr

            Logstream::setLogFile(tmp); // after this point no thread will be using old file

#if _WIN32
            if ( _file )
                fclose( _file );  // In Windows, we still have the old file open, close it now
#endif

#if 0 // enable to test redirection
            cout << "written to cout" << endl;
            cerr << "written to cerr" << endl;
            log() << "written to log()" << endl;
#endif

            _file = tmp;    // Save new file for next rotation
            return true;
        }
Пример #11
0
int ConfigServer::checkConfigVersion( bool upgrade ) {
    int cur = dbConfigVersion();
    if ( cur == VERSION )
        return 0;

    if ( cur == 0 ) {
        scoped_ptr<ScopedDbConnection> conn(
            ScopedDbConnection::getScopedDbConnection( _primary.getConnString() ) );

        // If the cluster has not previously been initialized, we need to set the version before using so
        // subsequent mongoses use the config data the same way.  This requires all three config servers online
        // initially.
        try {
            conn->get()->insert( "config.version" , BSON( "_id" << 1 << "version" << VERSION ) );
        }
        catch( DBException& ) {
            error() << "All config servers must initially be reachable for the cluster to be initialized." << endl;
            throw;
        }

        pool.flush();
        verify( VERSION == dbConfigVersion( conn->conn() ) );
        conn->done();
        return 0;
    }

    if ( cur == 2 ) {

        // need to upgrade
        verify( VERSION == 3 );
        if ( ! upgrade ) {
            log() << "newer version of mongo meta data\n"
                  << "need to --upgrade after shutting all mongos down"
                  << endl;
            return -9;
        }

        scoped_ptr<ScopedDbConnection> connPtr(
            ScopedDbConnection::getInternalScopedDbConnection( _primary.getConnString() ) );
        ScopedDbConnection& conn = *connPtr;

        // do a backup
        string backupName;
        {
            stringstream ss;
            ss << "config-backup-" << terseCurrentTime(false);
            backupName = ss.str();
        }
        log() << "backing up config to: " << backupName << endl;
        conn->copyDatabase( "config" , backupName );

        map<string,string> hostToShard;
        set<string> shards;
        // shards
        {
            unsigned n = 0;
            auto_ptr<DBClientCursor> c = conn->query( ShardNS::shard , BSONObj() );
            while ( c->more() ) {
                BSONObj o = c->next();
                string host = o["host"].String();

                string name = "";

                BSONElement id = o["_id"];
                if ( id.type() == String ) {
                    name = id.String();
                }
                else {
                    stringstream ss;
                    ss << "shard" << hostToShard.size();
                    name = ss.str();
                }

                hostToShard[host] = name;
                shards.insert( name );
                n++;
            }

            verify( n == hostToShard.size() );
            verify( n == shards.size() );

            conn->remove( ShardNS::shard , BSONObj() );

            for ( map<string,string>::iterator i=hostToShard.begin(); i != hostToShard.end(); i++ ) {
                conn->insert( ShardNS::shard , BSON( "_id" << i->second << "host" << i->first ) );
            }
        }

        // databases
        {
            auto_ptr<DBClientCursor> c = conn->query( ShardNS::database , BSONObj() );
            map<string,BSONObj> newDBs;
            unsigned n = 0;
            while ( c->more() ) {
                BSONObj old = c->next();
                n++;

                if ( old["name"].eoo() ) {
                    // already done
                    newDBs[old["_id"].String()] = old;
                    continue;
                }

                BSONObjBuilder b(old.objsize());
                b.appendAs( old["name"] , "_id" );

                BSONObjIterator i(old);
                while ( i.more() ) {
                    BSONElement e = i.next();
                    if ( strcmp( "_id" , e.fieldName() ) == 0 ||
                            strcmp( "name" , e.fieldName() ) == 0 ) {
                        continue;
                    }

                    b.append( e );
                }

                BSONObj x = b.obj();
                log() << old << "\n\t" << x << endl;
                newDBs[old["name"].String()] = x;
            }

            verify( n == newDBs.size() );

            conn->remove( ShardNS::database , BSONObj() );

            for ( map<string,BSONObj>::iterator i=newDBs.begin(); i!=newDBs.end(); i++ ) {
                conn->insert( ShardNS::database , i->second );
            }

        }

        // chunks
        {
            unsigned num = 0;
            map<string,BSONObj> chunks;
            auto_ptr<DBClientCursor> c = conn->query( ShardNS::chunk , BSONObj() );
            while ( c->more() ) {
                BSONObj x = c->next();
                BSONObjBuilder b;

                string id = Chunk::genID( x["ns"].String() , x["min"].Obj() );
                b.append( "_id" , id );

                BSONObjIterator i(x);
                while ( i.more() ) {
                    BSONElement e = i.next();
                    if ( strcmp( e.fieldName() , "_id" ) == 0 )
                        continue;
                    b.append( e );
                }

                BSONObj n = b.obj();
                log() << x << "\n\t" << n << endl;
                chunks[id] = n;
                num++;
            }

            verify( num == chunks.size() );

            conn->remove( ShardNS::chunk , BSONObj() );
            for ( map<string,BSONObj>::iterator i=chunks.begin(); i!=chunks.end(); i++ ) {
                conn->insert( ShardNS::chunk , i->second );
            }

        }

        conn->update( "config.version" , BSONObj() , BSON( "_id" << 1 << "version" << VERSION ) );
        conn.done();
        pool.flush();
        return 1;
    }

    log() << "don't know how to upgrade " << cur << " to " << VERSION << endl;
    return -8;
}
Пример #12
0
    int ConfigServer::checkConfigVersion( bool upgrade ) {
        int cur = dbConfigVersion();
        if ( cur == VERSION )
            return 0;

        if ( cur == 0 ) {
            ScopedDbConnection conn( _primary );
            conn->insert( "config.version" , BSON( "_id" << 1 << "version" << VERSION ) );
            pool.flush();
            assert( VERSION == dbConfigVersion( conn.conn() ) );
            conn.done();
            return 0;
        }

        if ( cur == 2 ) {

            // need to upgrade
            assert( VERSION == 3 );
            if ( ! upgrade ) {
                log() << "newer version of mongo meta data\n"
                      << "need to --upgrade after shutting all mongos down"
                      << endl;
                return -9;
            }

            ScopedDbConnection conn( _primary );

            // do a backup
            string backupName;
            {
                stringstream ss;
                ss << "config-backup-" << terseCurrentTime(false);
                backupName = ss.str();
            }
            log() << "backing up config to: " << backupName << endl;
            conn->copyDatabase( "config" , backupName );

            map<string,string> hostToShard;
            set<string> shards;
            // shards
            {
                unsigned n = 0;
                auto_ptr<DBClientCursor> c = conn->query( ShardNS::shard , BSONObj() );
                while ( c->more() ) {
                    BSONObj o = c->next();
                    string host = o["host"].String();

                    string name = "";

                    BSONElement id = o["_id"];
                    if ( id.type() == String ) {
                        name = id.String();
                    }
                    else {
                        stringstream ss;
                        ss << "shard" << hostToShard.size();
                        name = ss.str();
                    }

                    hostToShard[host] = name;
                    shards.insert( name );
                    n++;
                }

                assert( n == hostToShard.size() );
                assert( n == shards.size() );

                conn->remove( ShardNS::shard , BSONObj() );

                for ( map<string,string>::iterator i=hostToShard.begin(); i != hostToShard.end(); i++ ) {
                    conn->insert( ShardNS::shard , BSON( "_id" << i->second << "host" << i->first ) );
                }
            }

            // databases
            {
                auto_ptr<DBClientCursor> c = conn->query( ShardNS::database , BSONObj() );
                map<string,BSONObj> newDBs;
                unsigned n = 0;
                while ( c->more() ) {
                    BSONObj old = c->next();
                    n++;

                    if ( old["name"].eoo() ) {
                        // already done
                        newDBs[old["_id"].String()] = old;
                        continue;
                    }

                    BSONObjBuilder b(old.objsize());
                    b.appendAs( old["name"] , "_id" );

                    BSONObjIterator i(old);
                    while ( i.more() ) {
                        BSONElement e = i.next();
                        if ( strcmp( "_id" , e.fieldName() ) == 0 ||
                                strcmp( "name" , e.fieldName() ) == 0 ) {
                            continue;
                        }

                        b.append( e );
                    }

                    BSONObj x = b.obj();
                    log() << old << "\n\t" << x << endl;
                    newDBs[old["name"].String()] = x;
                }

                assert( n == newDBs.size() );

                conn->remove( ShardNS::database , BSONObj() );

                for ( map<string,BSONObj>::iterator i=newDBs.begin(); i!=newDBs.end(); i++ ) {
                    conn->insert( ShardNS::database , i->second );
                }

            }

            // chunks
            {
                unsigned num = 0;
                map<string,BSONObj> chunks;
                auto_ptr<DBClientCursor> c = conn->query( ShardNS::chunk , BSONObj() );
                while ( c->more() ) {
                    BSONObj x = c->next();
                    BSONObjBuilder b;

                    string id = Chunk::genID( x["ns"].String() , x["min"].Obj() );
                    b.append( "_id" , id );

                    BSONObjIterator i(x);
                    while ( i.more() ) {
                        BSONElement e = i.next();
                        if ( strcmp( e.fieldName() , "_id" ) == 0 )
                            continue;
                        b.append( e );
                    }

                    BSONObj n = b.obj();
                    log() << x << "\n\t" << n << endl;
                    chunks[id] = n;
                    num++;
                }

                assert( num == chunks.size() );

                conn->remove( ShardNS::chunk , BSONObj() );
                for ( map<string,BSONObj>::iterator i=chunks.begin(); i!=chunks.end(); i++ ) {
                    conn->insert( ShardNS::chunk , i->second );
                }

            }

            conn->update( "config.version" , BSONObj() , BSON( "_id" << 1 << "version" << VERSION ) );
            conn.done();
            pool.flush();
            return 1;
        }

        log() << "don't know how to upgrade " << cur << " to " << VERSION << endl;
        return -8;
    }