diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/log.cpp | 69 | ||||
-rw-r--r-- | util/log.h | 6 | ||||
-rw-r--r-- | util/net/sock.cpp | 85 | ||||
-rw-r--r-- | util/net/sock.h | 2 | ||||
-rw-r--r-- | util/scopeguard.h | 432 | ||||
-rw-r--r-- | util/version.cpp | 2 |
6 files changed, 562 insertions, 34 deletions
diff --git a/util/log.cpp b/util/log.cpp index bc48584..0dc75ed 100644 --- a/util/log.cpp +++ b/util/log.cpp @@ -25,12 +25,16 @@ using namespace std; #ifdef _WIN32 # include <io.h> +# include <fcntl.h> #else # include <cxxabi.h> # include <sys/file.h> #endif -//#include "../db/jsobj.h" +#ifdef _WIN32 +# define dup2 _dup2 // Microsoft headers use ISO C names +# define fileno _fileno +#endif namespace mongo { @@ -85,55 +89,72 @@ namespace mongo { } if ( _file ) { -#ifdef _WIN32 - cout << "log rotation net yet supported on windows" << endl; - return; -#else - struct tm t; - localtime_r( &_opened , &t ); +#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); + 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) { + 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; dbexit( EXIT_BADOPTIONS ); - assert(0); + 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); + // 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; - _opened = time(0); + _file = tmp; // Save new file for next rotation } private: - bool _enabled; string _path; bool _append; - FILE * _file; - time_t _opened; } loggingManager; @@ -507,6 +507,12 @@ namespace mongo { int x = errno; cout << "Failed to write to logfile: " << errnoWithDescription(x) << ": " << out << endl; } + +#ifdef POSIX_FADV_DONTNEED + // This only applies to pages that have already been flushed + RARELY posix_fadvise(fileno(logfile), 0, 0, POSIX_FADV_DONTNEED); +#endif + } _init(); } diff --git a/util/net/sock.cpp b/util/net/sock.cpp index 69c42f2..ac565c3 100644 --- a/util/net/sock.cpp +++ b/util/net/sock.cpp @@ -342,6 +342,67 @@ namespace mongo { // ------------ SSLManager ----------------- #ifdef MONGO_SSL + static unsigned long _ssl_id_callback(); + static void _ssl_locking_callback(int mode, int type, const char *file, int line); + + class SSLThreadInfo { + public: + + SSLThreadInfo() { + _id = ++_next; + CRYPTO_set_id_callback(_ssl_id_callback); + CRYPTO_set_locking_callback(_ssl_locking_callback); + } + + ~SSLThreadInfo() { + CRYPTO_set_id_callback(0); + } + + unsigned long id() const { return _id; } + + void lock_callback( int mode, int type, const char *file, int line ) { + if ( mode & CRYPTO_LOCK ) { + _mutex[type]->lock(); + } + else { + _mutex[type]->unlock(); + } + } + + static void init() { + while ( (int)_mutex.size() < CRYPTO_num_locks() ) + _mutex.push_back( new SimpleMutex("SSLThreadInfo") ); + } + + static SSLThreadInfo* get() { + SSLThreadInfo* me = _thread.get(); + if ( ! me ) { + me = new SSLThreadInfo(); + _thread.reset( me ); + } + return me; + } + + private: + unsigned _id; + + static AtomicUInt _next; + static vector<SimpleMutex*> _mutex; + static boost::thread_specific_ptr<SSLThreadInfo> _thread; + }; + + static unsigned long _ssl_id_callback() { + return SSLThreadInfo::get()->id(); + } + static void _ssl_locking_callback(int mode, int type, const char *file, int line) { + SSLThreadInfo::get()->lock_callback( mode , type , file , line ); + } + + AtomicUInt SSLThreadInfo::_next; + vector<SimpleMutex*> SSLThreadInfo::_mutex; + boost::thread_specific_ptr<SSLThreadInfo> SSLThreadInfo::_thread; + + SSLManager::SSLManager( bool client ) { _client = client; SSL_library_init(); @@ -352,6 +413,8 @@ namespace mongo { massert( 15864 , mongoutils::str::stream() << "can't create SSL Context: " << ERR_error_string(ERR_get_error(), NULL) , _context ); SSL_CTX_set_options( _context, SSL_OP_ALL); + SSLThreadInfo::init(); + SSLThreadInfo::get(); } void SSLManager::setupPubPriv( const string& privateKeyFile , const string& publicKeyFile ) { @@ -387,6 +450,7 @@ namespace mongo { } SSL * SSLManager::secure( int fd ) { + SSLThreadInfo::get(); SSL * ssl = SSL_new( _context ); massert( 15861 , "can't create SSL" , ssl ); SSL_set_fd( ssl , fd ); @@ -415,13 +479,18 @@ namespace mongo { _bytesOut = 0; _bytesIn = 0; #ifdef MONGO_SSL + _ssl = 0; _sslAccepted = 0; #endif } void Socket::close() { #ifdef MONGO_SSL - _ssl.reset(); + if ( _ssl ) { + SSL_shutdown( _ssl ); + SSL_free( _ssl ); + _ssl = 0; + } #endif if ( _fd >= 0 ) { closesocket( _fd ); @@ -433,8 +502,8 @@ namespace mongo { void Socket::secure( SSLManager * ssl ) { assert( ssl ); assert( _fd >= 0 ); - _ssl.reset( ssl->secure( _fd ) ); - SSL_connect( _ssl.get() ); + _ssl = ssl->secure( _fd ); + SSL_connect( _ssl ); } void Socket::secureAccepted( SSLManager * ssl ) { @@ -446,8 +515,8 @@ namespace mongo { #ifdef MONGO_SSL if ( _sslAccepted ) { assert( _fd ); - _ssl.reset( _sslAccepted->secure( _fd ) ); - SSL_accept( _ssl.get() ); + _ssl = _sslAccepted->secure( _fd ); + SSL_accept( _ssl ); _sslAccepted = 0; } #endif @@ -510,7 +579,7 @@ namespace mongo { int Socket::_send( const char * data , int len ) { #ifdef MONGO_SSL if ( _ssl ) { - return SSL_write( _ssl.get() , data , len ); + return SSL_write( _ssl , data , len ); } #endif return ::send( _fd , data , len , portSendFlags ); @@ -524,7 +593,7 @@ namespace mongo { #ifdef MONGO_SSL if ( _ssl ) { - log() << "SSL Error ret: " << ret << " err: " << SSL_get_error( _ssl.get() , ret ) + log() << "SSL Error ret: " << ret << " err: " << SSL_get_error( _ssl , ret ) << " " << ERR_error_string(ERR_get_error(), NULL) << endl; } @@ -679,7 +748,7 @@ namespace mongo { int Socket::_recv( char *buf, int max ) { #ifdef MONGO_SSL if ( _ssl ){ - return SSL_read( _ssl.get() , buf , max ); + return SSL_read( _ssl , buf , max ); } #endif return ::recv( _fd , buf , max , portRecvFlags ); diff --git a/util/net/sock.h b/util/net/sock.h index 1cd5133..f91c288 100644 --- a/util/net/sock.h +++ b/util/net/sock.h @@ -243,7 +243,7 @@ namespace mongo { long long _bytesOut; #ifdef MONGO_SSL - shared_ptr<SSL> _ssl; + SSL* _ssl; SSLManager * _sslAccepted; #endif diff --git a/util/scopeguard.h b/util/scopeguard.h new file mode 100644 index 0000000..8ced04f --- /dev/null +++ b/util/scopeguard.h @@ -0,0 +1,432 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2000 Andrei Alexandrescu +// Copyright (c) 2000 Petru Marginean +// Copyright (c) 2005 Joshua Lehrer +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SCOPEGUARD_H_ +#define LOKI_SCOPEGUARD_H_ + +namespace mongo +{ + + //////////////////////////////////////////////////////////////////////////////// + /// \class RefToValue + /// + /// Transports a reference as a value + /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard + //////////////////////////////////////////////////////////////////////////////// + + template <class T> + class RefToValue + { + public: + + RefToValue(T& ref) : ref_(ref) + {} + + RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) + {} + + operator T& () const + { + return ref_; + } + + private: + // Disable - not implemented + RefToValue(); + RefToValue& operator=(const RefToValue&); + + T& ref_; + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// RefToValue creator. + //////////////////////////////////////////////////////////////////////////////// + + template <class T> + inline RefToValue<T> ByRef(T& t) + { + return RefToValue<T>(t); + } + + + + + //////////////////////////////////////////// + /// ScopeGuard + /* + Trivial example for use: + + FILE* f = fopen("myfile.txt", "w+"); + if (!f) + return error; + ON_BLOCK_EXIT(fclose, f); + + + More complicated example: + + ScopeGuard guard = MakeGuard(my_rollback_func, myparam); + ... + if (successful) { + guard.Dismiss(); + return; + } + // guard is still active here and will fire at scope exit + ... + + + */ + + + class ScopeGuardImplBase + { + ScopeGuardImplBase& operator =(const ScopeGuardImplBase&); + + protected: + + ~ScopeGuardImplBase() + {} + + ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() + : dismissed_(other.dismissed_) + { + other.Dismiss(); + } + + template <typename J> + static void SafeExecute(J& j) throw() + { + if (!j.dismissed_) + try + { + j.Execute(); + } + catch(...) + {} + } + + mutable bool dismissed_; + + public: + ScopeGuardImplBase() throw() : dismissed_(false) + {} + + void Dismiss() const throw() + { + dismissed_ = true; + } + }; + + //////////////////////////////////////////////////////////////// + /// + /// \typedef typedef const ScopeGuardImplBase& ScopeGuard + /// + /// See Andrei's and Petru Marginean's CUJ article + /// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm + /// + /// Changes to the original code by Joshua Lehrer: + /// http://www.lehrerfamily.com/scopeguard.html + //////////////////////////////////////////////////////////////// + + typedef const ScopeGuardImplBase& ScopeGuard; + + template <typename F> + class ScopeGuardImpl0 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl0<F> MakeGuard(F fun) + { + return ScopeGuardImpl0<F>(fun); + } + + ~ScopeGuardImpl0() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(); + } + + protected: + ScopeGuardImpl0(F fun) : fun_(fun) + {} + + F fun_; + }; + + template <typename F> + inline ScopeGuardImpl0<F> MakeGuard(F fun) + { + return ScopeGuardImpl0<F>::MakeGuard(fun); + } + + template <typename F, typename P1> + class ScopeGuardImpl1 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) + { + return ScopeGuardImpl1<F, P1>(fun, p1); + } + + ~ScopeGuardImpl1() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_); + } + + protected: + ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) + {} + + F fun_; + const P1 p1_; + }; + + template <typename F, typename P1> + inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) + { + return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1); + } + + template <typename F, typename P1, typename P2> + class ScopeGuardImpl2: public ScopeGuardImplBase + { + public: + static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) + { + return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2); + } + + ~ScopeGuardImpl2() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_, p2_); + } + + protected: + ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + }; + + template <typename F, typename P1, typename P2> + inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) + { + return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2); + } + + template <typename F, typename P1, typename P2, typename P3> + class ScopeGuardImpl3 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) + { + return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3); + } + + ~ScopeGuardImpl3() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_, p2_, p3_); + } + + protected: + ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + }; + + template <typename F, typename P1, typename P2, typename P3> + inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) + { + return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3); + } + + //************************************************************ + + template <class Obj, typename MemFun> + class ObjScopeGuardImpl0 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) + { + return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun); + } + + ~ObjScopeGuardImpl0() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(); + } + + protected: + ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) + {} + + Obj& obj_; + MemFun memFun_; + }; + + template <class Obj, typename MemFun> + inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) + { + return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun); + } + + template <typename Ret, class Obj1, class Obj2> + inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 &obj) + { + return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(obj,memFun); + } + + template <typename Ret, class Obj1, class Obj2> + inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 *obj) + { + return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(*obj,memFun); + } + + template <class Obj, typename MemFun, typename P1> + class ObjScopeGuardImpl1 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) + { + return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1); + } + + ~ObjScopeGuardImpl1() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(p1_); + } + + protected: + ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1) + {} + + Obj& obj_; + MemFun memFun_; + const P1 p1_; + }; + + template <class Obj, typename MemFun, typename P1> + inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) + { + return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> + inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 &obj, P1b p1) + { + return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(obj,memFun,p1); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> + inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 *obj, P1b p1) + { + return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(*obj,memFun,p1); + } + + template <class Obj, typename MemFun, typename P1, typename P2> + class ObjScopeGuardImpl2 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) + { + return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2); + } + + ~ObjScopeGuardImpl2() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(p1_, p2_); + } + + protected: + ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) + {} + + Obj& obj_; + MemFun memFun_; + const P1 p1_; + const P2 p2_; + }; + + template <class Obj, typename MemFun, typename P1, typename P2> + inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) + { + return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b> + inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 &obj, P1b p1, P2b p2) + { + return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(obj,memFun,p1,p2); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b> + inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 *obj, P1b p1, P2b p2) + { + return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(*obj,memFun,p1,p2); + } + +} // namespace Loki + +#define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2 +#define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2) +#define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__) + +#ifdef __GNUC__ +#define ON_BLOCK_EXIT ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) __attribute__ ((unused)) = MakeGuard +#define ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) __attribute__ ((unused)) = MakeObjGuard +#else +#define ON_BLOCK_EXIT ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeGuard +#define ON_BLOCK_EXIT_OBJ ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = MakeObjGuard +#endif + +#endif //LOKI_SCOPEGUARD_H_ diff --git a/util/version.cpp b/util/version.cpp index c43180c..883c208 100644 --- a/util/version.cpp +++ b/util/version.cpp @@ -38,7 +38,7 @@ namespace mongo { * 1.2.3-rc4-pre- * If you really need to do something else you'll need to fix _versionArray() */ - const char versionString[] = "2.0.2"; + const char versionString[] = "2.0.3"; // See unit test for example outputs static BSONArray _versionArray(const char* version){ |