0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
mongodb/util/goodies.h

604 lines
15 KiB
C
Raw Normal View History

// @file goodies.h
// miscellaneous
2008-06-06 15:43:15 +02:00
/* Copyright 2009 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2008-06-06 15:43:15 +02:00
#pragma once
2010-04-25 00:25:58 +02:00
#include "../bson/util/misc.h"
#include "concurrency/mutex.h"
2010-04-24 22:43:09 +02:00
2009-01-14 23:09:51 +01:00
namespace mongo {
/* @return a dump of the buffer as hex byte ascii output */
string hexdump(const char *data, unsigned len);
/**
* @return if this name has an increasing counter associated, return the value
* otherwise 0
*/
unsigned setThreadName(const char * name);
2010-06-30 00:10:40 +02:00
string getThreadName();
2011-01-04 06:40:41 +01:00
2010-05-05 22:33:35 +02:00
template<class T>
2011-01-04 06:40:41 +01:00
inline string ToString(const T& t) {
2010-05-05 22:33:35 +02:00
stringstream s;
s << t;
return s.str();
}
#if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__) && !defined(__openbsd__) && !defined(__sun__)
2009-01-14 23:09:51 +01:00
} // namespace mongo
2008-06-06 15:43:15 +02:00
#include <pthread.h>
2009-09-22 02:32:17 +02:00
#include <execinfo.h>
2009-01-14 23:09:51 +01:00
namespace mongo {
inline pthread_t GetCurrentThreadId() {
return pthread_self();
}
2009-01-14 23:09:51 +01:00
/* use "addr2line -CFe <exe>" to parse. */
inline void printStackTrace( ostream &o = cout ) {
void *b[20];
2008-12-29 02:28:49 +01:00
int size = backtrace(b, 20);
for (int i = 0; i < size; i++)
o << hex << b[i] << dec << ' ';
o << endl;
char **strings;
strings = backtrace_symbols(b, size);
for (int i = 0; i < size; i++)
o << ' ' << strings[i] << '\n';
2010-08-31 17:16:18 +02:00
o.flush();
free (strings);
}
2008-06-27 20:35:05 +02:00
#else
2009-08-12 20:54:53 +02:00
inline void printStackTrace( ostream &o = cout ) { }
2008-06-06 15:43:15 +02:00
#endif
bool isPrime(int n);
int nextPrime(int n);
inline void dumpmemory(const char *data, int len) {
if ( len > 1024 )
len = 1024;
try {
const char *q = data;
const char *p = q;
while ( len > 0 ) {
for ( int i = 0; i < 16; i++ ) {
if ( *p >= 32 && *p <= 126 )
cout << *p;
else
cout << '.';
p++;
}
cout << " ";
p -= 16;
for ( int i = 0; i < 16; i++ )
cout << (unsigned) ((unsigned char)*p++) << ' ';
cout << endl;
len -= 16;
2008-12-29 02:28:49 +01:00
}
2011-01-04 06:40:41 +01:00
}
catch (...) {
2008-12-29 02:28:49 +01:00
}
}
2008-06-06 15:43:15 +02:00
2009-12-11 20:29:10 +01:00
// PRINT(2+2); prints "2+2: 4"
#define MONGO_PRINT(x) cout << #x ": " << (x) << endl
#define PRINT MONGO_PRINT
2009-12-11 20:29:10 +01:00
// PRINTFL; prints file:line
#define MONGO_PRINTFL cout << __FILE__ ":" << __LINE__ << endl
#define PRINTFL MONGO_PRINTFL
2009-12-11 20:29:10 +01:00
2008-06-06 15:43:15 +02:00
#undef assert
2010-04-24 02:09:32 +02:00
#define assert MONGO_assert
2008-06-06 15:43:15 +02:00
struct WrappingInt {
WrappingInt() {
x = 0;
}
WrappingInt(unsigned z) : x(z) { }
unsigned x;
operator unsigned() const {
return x;
}
2009-12-02 01:28:27 +01:00
static int diff(unsigned a, unsigned b) {
return a-b;
}
bool operator<=(WrappingInt r) {
// platform dependent
int df = (r.x - x);
return df >= 0;
}
bool operator>(WrappingInt r) {
return !(r<=*this);
}
};
2008-06-06 15:43:15 +02:00
/*
2011-01-04 06:40:41 +01:00
class DebugMutex : boost::noncopyable {
2011-01-04 06:40:41 +01:00
friend class lock;
mongo::mutex m;
int locked;
public:
2011-01-04 06:40:41 +01:00
DebugMutex() : locked(0); { }
bool isLocked() { return locked; }
};
2008-07-31 19:37:32 +02:00
*/
2008-07-31 19:37:32 +02:00
//typedef scoped_lock lock;
inline bool startsWith(const char *str, const char *prefix) {
size_t l = strlen(prefix);
if ( strlen(str) < l ) return false;
return strncmp(str, prefix, l) == 0;
}
2010-04-27 20:37:41 +02:00
inline bool startsWith(string s, string p) { return startsWith(s.c_str(), p.c_str()); }
inline bool endsWith(const char *p, const char *suffix) {
size_t a = strlen(p);
size_t b = strlen(suffix);
if ( b > a ) return false;
return strcmp(p + a - b, suffix) == 0;
}
inline unsigned long swapEndian(unsigned long x) {
return
((x & 0xff) << 24) |
((x & 0xff00) << 8) |
((x & 0xff0000) >> 8) |
((x & 0xff000000) >> 24);
}
#if defined(BOOST_LITTLE_ENDIAN)
inline unsigned long fixEndian(unsigned long x) {
return x;
}
#else
inline unsigned long fixEndian(unsigned long x) {
return swapEndian(x);
}
#endif
2011-01-04 06:40:41 +01:00
#if !defined(_WIN32)
typedef int HANDLE;
inline void strcpy_s(char *dst, unsigned len, const char *src) {
2010-11-24 16:20:34 +01:00
assert( strlen(src) < len );
strcpy(dst, src);
}
#else
typedef void *HANDLE;
#endif
2011-01-04 06:40:41 +01:00
2009-10-13 18:55:23 +02:00
/* thread local "value" rather than a pointer
good for things which have copy constructors (and the copy constructor is fast enough)
2011-01-04 06:40:41 +01:00
e.g.
2009-10-13 18:55:23 +02:00
ThreadLocalValue<int> myint;
*/
template<class T>
class ThreadLocalValue {
public:
2009-10-13 18:55:23 +02:00
ThreadLocalValue( T def = 0 ) : _default( def ) { }
2010-10-07 06:10:18 +02:00
T get() const {
2009-10-13 18:55:23 +02:00
T * val = _val.get();
if ( val )
return *val;
2009-10-13 18:55:23 +02:00
return _default;
}
2009-12-03 19:48:45 +01:00
2009-10-13 18:55:23 +02:00
void set( const T& i ) {
T *v = _val.get();
2011-01-04 06:40:41 +01:00
if( v ) {
2009-10-13 18:55:23 +02:00
*v = i;
return;
}
v = new T(i);
_val.reset( v );
}
2009-12-03 19:48:45 +01:00
private:
2009-10-13 18:55:23 +02:00
boost::thread_specific_ptr<T> _val;
const T _default;
};
2009-01-14 23:09:51 +01:00
class ProgressMeter : boost::noncopyable {
2009-10-05 21:09:18 +02:00
public:
2011-01-04 06:40:41 +01:00
ProgressMeter( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) {
reset( total , secondsBetween , checkInterval );
}
2011-01-04 06:40:41 +01:00
ProgressMeter() {
_active = 0;
}
2011-01-04 06:40:41 +01:00
void reset( unsigned long long total , int secondsBetween = 3 , int checkInterval = 100 ) {
_total = total;
_secondsBetween = secondsBetween;
_checkInterval = checkInterval;
_done = 0;
_hits = 0;
_lastTime = (int)time(0);
_active = 1;
}
2011-01-04 06:40:41 +01:00
void finished() {
_active = 0;
}
2011-01-04 06:40:41 +01:00
bool isActive() {
return _active;
2009-10-05 21:09:18 +02:00
}
2011-01-04 06:40:41 +01:00
/**
* @return if row was printed
*/
2011-01-04 06:40:41 +01:00
bool hit( int n = 1 ) {
if ( ! _active ) {
cout << "warning: hit on in-active ProgressMeter" << endl;
return false;
}
2009-10-05 21:09:18 +02:00
_done += n;
_hits++;
if ( _hits % _checkInterval )
return false;
2011-01-04 06:40:41 +01:00
2009-10-06 22:17:11 +02:00
int t = (int) time(0);
2009-10-05 21:09:18 +02:00
if ( t - _lastTime < _secondsBetween )
return false;
2011-01-04 06:40:41 +01:00
if ( _total > 0 ) {
int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
cout << "\t\t" << _done << "/" << _total << "\t" << per << "%" << endl;
}
2009-10-05 21:09:18 +02:00
_lastTime = t;
return true;
2009-10-05 21:09:18 +02:00
}
2011-01-04 06:40:41 +01:00
unsigned long long done() {
2009-10-05 21:09:18 +02:00
return _done;
}
2011-01-04 06:40:41 +01:00
unsigned long long hits() {
2009-10-05 21:09:18 +02:00
return _hits;
}
string toString() const {
if ( ! _active )
return "";
stringstream buf;
buf << _done << "/" << _total << " " << (_done*100)/_total << "%";
return buf.str();
}
bool operator==( const ProgressMeter& other ) const {
return this == &other;
}
2009-10-05 21:09:18 +02:00
private:
bool _active;
2011-01-04 06:40:41 +01:00
2010-11-28 05:48:42 +01:00
unsigned long long _total;
2009-10-05 21:09:18 +02:00
int _secondsBetween;
int _checkInterval;
2010-11-28 05:48:42 +01:00
unsigned long long _done;
unsigned long long _hits;
2009-10-05 21:09:18 +02:00
int _lastTime;
};
class ProgressMeterHolder : boost::noncopyable {
public:
ProgressMeterHolder( ProgressMeter& pm )
2011-01-04 06:40:41 +01:00
: _pm( pm ) {
}
2011-01-04 06:40:41 +01:00
~ProgressMeterHolder() {
_pm.finished();
}
2011-01-04 06:40:41 +01:00
ProgressMeter* operator->() {
return &_pm;
}
2011-01-04 06:40:41 +01:00
bool hit( int n = 1 ) {
return _pm.hit( n );
}
2011-01-04 06:40:41 +01:00
void finished() {
_pm.finished();
}
2011-01-04 06:40:41 +01:00
bool operator==( const ProgressMeter& other ) {
return _pm == other;
}
2011-01-04 06:40:41 +01:00
private:
ProgressMeter& _pm;
};
class TicketHolder {
public:
2010-05-26 06:46:49 +02:00
TicketHolder( int num ) : _mutex("TicketHolder") {
_outof = num;
_num = num;
}
2011-01-04 06:40:41 +01:00
bool tryAcquire() {
scoped_lock lk( _mutex );
2011-01-04 06:40:41 +01:00
if ( _num <= 0 ) {
if ( _num < 0 ) {
cerr << "DISASTER! in TicketHolder" << endl;
}
return false;
}
_num--;
return true;
}
2011-01-04 06:40:41 +01:00
void release() {
scoped_lock lk( _mutex );
_num++;
}
2011-01-04 06:40:41 +01:00
void resize( int newSize ) {
scoped_lock lk( _mutex );
int used = _outof - _num;
2011-01-04 06:40:41 +01:00
if ( used > newSize ) {
cout << "ERROR: can't resize since we're using (" << used << ") more than newSize(" << newSize << ")" << endl;
return;
}
2011-01-04 06:40:41 +01:00
_outof = newSize;
_num = _outof - used;
}
2010-08-13 00:56:09 +02:00
int available() const {
return _num;
}
2010-08-13 00:56:09 +02:00
int used() const {
return _outof - _num;
}
2010-08-13 00:56:09 +02:00
int outof() const { return _outof; }
private:
int _outof;
int _num;
mongo::mutex _mutex;
};
class TicketHolderReleaser {
public:
2011-01-04 06:40:41 +01:00
TicketHolderReleaser( TicketHolder * holder ) {
_holder = holder;
}
2011-01-04 06:40:41 +01:00
~TicketHolderReleaser() {
_holder->release();
}
private:
TicketHolder * _holder;
};
2010-02-26 17:33:20 +01:00
/**
* this is a thread safe string
* you will never get a bad pointer, though data may be mungedd
*/
class ThreadSafeString {
public:
ThreadSafeString( size_t size=256 )
2011-01-04 06:40:41 +01:00
: _size( 256 ) , _buf( new char[256] ) {
2010-02-26 17:33:20 +01:00
memset( _buf , 0 , _size );
}
2010-02-26 18:07:46 +01:00
ThreadSafeString( const ThreadSafeString& other )
2011-01-04 06:40:41 +01:00
: _size( other._size ) , _buf( new char[_size] ) {
2010-02-26 18:07:46 +01:00
strncpy( _buf , other._buf , _size );
}
2011-01-04 06:40:41 +01:00
~ThreadSafeString() {
2010-02-26 18:07:46 +01:00
delete[] _buf;
2010-02-26 17:33:20 +01:00
_buf = 0;
}
2011-01-04 06:40:41 +01:00
2010-07-19 18:39:14 +02:00
string toString() const {
2010-02-26 18:07:46 +01:00
string s = _buf;
return s;
2010-02-26 17:33:20 +01:00
}
2011-01-04 06:40:41 +01:00
ThreadSafeString& operator=( const char * str ) {
2010-02-26 17:33:20 +01:00
size_t s = strlen(str);
if ( s >= _size - 2 )
s = _size - 2;
strncpy( _buf , str , s );
_buf[s] = 0;
return *this;
}
2011-01-04 06:40:41 +01:00
2010-02-26 18:07:46 +01:00
bool operator==( const ThreadSafeString& other ) const {
return strcmp( _buf , other._buf ) == 0;
}
bool operator==( const char * str ) const {
return strcmp( _buf , str ) == 0;
}
bool operator!=( const char * str ) const {
2010-06-06 02:55:11 +02:00
return strcmp( _buf , str ) != 0;
2010-02-26 18:07:46 +01:00
}
2010-02-26 17:33:20 +01:00
bool empty() const {
return _buf == 0 || _buf[0] == 0;
2010-02-26 17:33:20 +01:00
}
private:
size_t _size;
2011-01-04 06:40:41 +01:00
char * _buf;
2010-02-26 17:33:20 +01:00
};
ostream& operator<<( ostream &s, const ThreadSafeString &o );
inline bool isNumber( char c ) {
return c >= '0' && c <= '9';
}
2010-04-21 22:14:28 +02:00
inline unsigned stringToNum(const char *str) {
unsigned x = 0;
const char *p = str;
while( 1 ) {
if( !isNumber(*p) ) {
if( *p == 0 && p != str )
break;
throw 0;
}
x = x * 10 + *p++ - '0';
}
return x;
}
2011-01-04 06:40:41 +01:00
// for convenience, '{' is greater than anything and stops number parsing
inline int lexNumCmp( const char *s1, const char *s2 ) {
2010-08-26 00:30:51 +02:00
//cout << "START : " << s1 << "\t" << s2 << endl;
while( *s1 && *s2 ) {
2010-08-26 00:30:51 +02:00
bool p1 = ( *s1 == (char)255 );
bool p2 = ( *s2 == (char)255 );
//cout << "\t\t " << p1 << "\t" << p2 << endl;
if ( p1 && !p2 )
return 1;
if ( p2 && !p1 )
return -1;
2011-01-04 06:40:41 +01:00
bool n1 = isNumber( *s1 );
bool n2 = isNumber( *s2 );
2011-01-04 06:40:41 +01:00
if ( n1 && n2 ) {
2010-08-26 21:17:41 +02:00
// get rid of leading 0s
while ( *s1 == '0' ) s1++;
while ( *s2 == '0' ) s2++;
char * e1 = (char*)s1;
char * e2 = (char*)s2;
// find length
// if end of string, will break immediately ('\0')
while ( isNumber (*e1) ) e1++;
while ( isNumber (*e2) ) e2++;
int len1 = (int)(e1-s1);
int len2 = (int)(e2-s2);
2010-08-26 21:17:41 +02:00
int result;
// if one is longer than the other, return
if ( len1 > len2 ) {
return 1;
2010-08-26 21:17:41 +02:00
}
else if ( len2 > len1 ) {
return -1;
2010-08-26 21:17:41 +02:00
}
// if the lengths are equal, just strcmp
else if ( (result = strncmp(s1, s2, len1)) != 0 ) {
return result;
}
// otherwise, the numbers are equal
s1 = e1;
s2 = e2;
continue;
2011-01-04 06:40:41 +01:00
}
if ( n1 )
return 1;
2011-01-04 06:40:41 +01:00
if ( n2 )
return -1;
2011-01-04 06:40:41 +01:00
if ( *s1 > *s2 )
return 1;
2011-01-04 06:40:41 +01:00
if ( *s2 > *s1 )
return -1;
2011-01-04 06:40:41 +01:00
s1++; s2++;
}
2011-01-04 06:40:41 +01:00
if ( *s1 )
return 1;
if ( *s2 )
return -1;
return 0;
}
2010-05-20 01:27:04 +02:00
/** A generic pointer type for function arguments.
* It will convert from any pointer type except auto_ptr.
* Semantics are the same as passing the pointer returned from get()
* const ptr<T> => T * const
* ptr<const T> => T const * or const T*
*/
template <typename T>
2011-01-04 06:40:41 +01:00
struct ptr {
2010-05-20 01:27:04 +02:00
ptr() : _p(NULL) {}
// convert to ptr<T>
2010-05-20 04:47:15 +02:00
ptr(T* p) : _p(p) {} // needed for NULL
template<typename U> ptr(U* p) : _p(p) {}
template<typename U> ptr(const ptr<U>& p) : _p(p) {}
2010-05-20 13:38:47 +02:00
template<typename U> ptr(const boost::shared_ptr<U>& p) : _p(p.get()) {}
template<typename U> ptr(const boost::scoped_ptr<U>& p) : _p(p.get()) {}
2010-05-20 04:47:15 +02:00
//template<typename U> ptr(const auto_ptr<U>& p) : _p(p.get()) {}
2011-01-04 06:40:41 +01:00
2010-05-20 01:27:04 +02:00
// assign to ptr<T>
2010-05-20 04:47:15 +02:00
ptr& operator= (T* p) { _p = p; return *this; } // needed for NULL
template<typename U> ptr& operator= (U* p) { _p = p; return *this; }
template<typename U> ptr& operator= (const ptr<U>& p) { _p = p; return *this; }
2010-05-20 13:38:47 +02:00
template<typename U> ptr& operator= (const boost::shared_ptr<U>& p) { _p = p.get(); return *this; }
template<typename U> ptr& operator= (const boost::scoped_ptr<U>& p) { _p = p.get(); return *this; }
2010-05-20 04:47:15 +02:00
//template<typename U> ptr& operator= (const auto_ptr<U>& p) { _p = p.get(); return *this; }
2010-05-20 01:27:04 +02:00
// use
T* operator->() const { return _p; }
2010-05-20 04:47:15 +02:00
T& operator*() const { return *_p; }
2010-05-20 01:27:04 +02:00
// convert from ptr<T>
operator T* () const { return _p; }
private:
T* _p;
};
/** Hmmmm */
using namespace boost;
2009-01-14 23:09:51 +01:00
} // namespace mongo