~ubuntu-branches/ubuntu/trusty/mongodb/trusty-proposed

« back to all changes in this revision

Viewing changes to util/goodies.h

  • Committer: Bazaar Package Importer
  • Author(s): Antonin Kral
  • Date: 2010-01-29 19:48:45 UTC
  • Revision ID: james.westby@ubuntu.com-20100129194845-8wbmkf626fwcavc9
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// goodies.h
 
2
// miscellaneous junk
 
3
 
 
4
/*    Copyright 2009 10gen Inc.
 
5
 *
 
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
 
7
 *    you may not use this file except in compliance with the License.
 
8
 *    You may obtain a copy of the License at
 
9
 *
 
10
 *    http://www.apache.org/licenses/LICENSE-2.0
 
11
 *
 
12
 *    Unless required by applicable law or agreed to in writing, software
 
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
 
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
15
 *    See the License for the specific language governing permissions and
 
16
 *    limitations under the License.
 
17
 */
 
18
 
 
19
#pragma once
 
20
 
 
21
#if defined(_WIN32)
 
22
#  include <windows.h>
 
23
#endif
 
24
 
 
25
namespace mongo {
 
26
 
 
27
#if !defined(_WIN32) && !defined(NOEXECINFO)
 
28
 
 
29
} // namespace mongo
 
30
 
 
31
#include <pthread.h>
 
32
#include <execinfo.h>
 
33
 
 
34
namespace mongo {
 
35
 
 
36
    inline pthread_t GetCurrentThreadId() {
 
37
        return pthread_self();
 
38
    }
 
39
 
 
40
    /* use "addr2line -CFe <exe>" to parse. */
 
41
    inline void printStackTrace( ostream &o = cout ) {
 
42
        void *b[20];
 
43
        size_t size;
 
44
        char **strings;
 
45
        size_t i;
 
46
 
 
47
        size = backtrace(b, 20);
 
48
        strings = backtrace_symbols(b, size);
 
49
 
 
50
        for (i = 0; i < size; i++)
 
51
            o << hex << b[i] << dec << ' ';
 
52
        o << '\n';
 
53
        for (i = 0; i < size; i++)
 
54
            o << ' ' << strings[i] << '\n';
 
55
 
 
56
        free (strings);
 
57
    }
 
58
#else
 
59
    inline void printStackTrace( ostream &o = cout ) { }
 
60
#endif
 
61
 
 
62
    /* set to TRUE if we are exiting */
 
63
    extern bool goingAway;
 
64
 
 
65
    /* find the multimap member which matches a particular key and value.
 
66
 
 
67
       note this can be slow if there are a lot with the same key.
 
68
    */
 
69
    template<class C,class K,class V> inline typename C::iterator kv_find(C& c, const K& k,const V& v) {
 
70
        pair<typename C::iterator,typename C::iterator> p = c.equal_range(k);
 
71
 
 
72
        for ( typename C::iterator it=p.first; it!=p.second; ++it)
 
73
            if ( it->second == v )
 
74
                return it;
 
75
 
 
76
        return c.end();
 
77
    }
 
78
 
 
79
    bool isPrime(int n);
 
80
    int nextPrime(int n);
 
81
 
 
82
    inline void dumpmemory(const char *data, int len) {
 
83
        if ( len > 1024 )
 
84
            len = 1024;
 
85
        try {
 
86
            const char *q = data;
 
87
            const char *p = q;
 
88
            while ( len > 0 ) {
 
89
                for ( int i = 0; i < 16; i++ ) {
 
90
                    if ( *p >= 32 && *p <= 126 )
 
91
                        cout << *p;
 
92
                    else
 
93
                        cout << '.';
 
94
                    p++;
 
95
                }
 
96
                cout << "  ";
 
97
                p -= 16;
 
98
                for ( int i = 0; i < 16; i++ )
 
99
                    cout << (unsigned) ((unsigned char)*p++) << ' ';
 
100
                cout << endl;
 
101
                len -= 16;
 
102
            }
 
103
        } catch (...) {
 
104
        }
 
105
    }
 
106
 
 
107
// PRINT(2+2);  prints "2+2: 4"
 
108
#define PRINT(x) cout << #x ": " << (x) << endl
 
109
// PRINTFL; prints file:line
 
110
#define PRINTFL cout << __FILE__ ":" << __LINE__ << endl
 
111
 
 
112
#undef yassert
 
113
 
 
114
#undef assert
 
115
#define assert xassert
 
116
#define yassert 1
 
117
 
 
118
    struct WrappingInt {
 
119
        WrappingInt() {
 
120
            x = 0;
 
121
        }
 
122
        WrappingInt(unsigned z) : x(z) { }
 
123
        volatile unsigned x;
 
124
        operator unsigned() const {
 
125
            return x;
 
126
        }
 
127
 
 
128
        // returns original value (like x++)
 
129
        WrappingInt atomicIncrement(){
 
130
#if defined(_WIN32)
 
131
            // InterlockedIncrement returns the new value
 
132
            return InterlockedIncrement((volatile long*)&x)-1; //long is 32bits in Win64
 
133
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
 
134
            // this is in GCC >= 4.1
 
135
            return __sync_fetch_and_add(&x, 1);
 
136
#elif defined(__GNUC__)  && (defined(__i386__) || defined(__x86_64__))
 
137
            // from boost 1.39 interprocess/detail/atomic.hpp
 
138
            int r;
 
139
            int val = 1;
 
140
            asm volatile
 
141
            (
 
142
               "lock\n\t"
 
143
               "xadd %1, %0":
 
144
               "+m"( x ), "=r"( r ): // outputs (%0, %1)
 
145
               "1"( val ): // inputs (%2 == %1)
 
146
               "memory", "cc" // clobbers
 
147
            );
 
148
            return r;
 
149
#else
 
150
#  error "unsupported compiler or platform"
 
151
#endif
 
152
        }
 
153
 
 
154
        static int diff(unsigned a, unsigned b) {
 
155
            return a-b;
 
156
        }
 
157
        bool operator<=(WrappingInt r) {
 
158
            // platform dependent
 
159
            int df = (r.x - x);
 
160
            return df >= 0;
 
161
        }
 
162
        bool operator>(WrappingInt r) {
 
163
            return !(r<=*this);
 
164
        }
 
165
    };
 
166
 
 
167
} // namespace mongo
 
168
 
 
169
#include <ctime>
 
170
 
 
171
namespace mongo {
 
172
 
 
173
    inline void time_t_to_String(time_t t, char *buf) {
 
174
#if defined(_WIN32)
 
175
        ctime_s(buf, 64, &t);
 
176
#else
 
177
        ctime_r(&t, buf);
 
178
#endif
 
179
        buf[24] = 0; // don't want the \n
 
180
    }
 
181
 
 
182
#define asctime _asctime_not_threadsafe_
 
183
#define gmtime _gmtime_not_threadsafe_
 
184
#define localtime _localtime_not_threadsafe_
 
185
#define ctime _ctime_is_not_threadsafe_
 
186
 
 
187
#if defined(_WIN32) || defined(__sunos__)
 
188
    inline void sleepsecs(int s) {
 
189
        boost::xtime xt;
 
190
        boost::xtime_get(&xt, boost::TIME_UTC);
 
191
        xt.sec += s;
 
192
        boost::thread::sleep(xt);
 
193
    }
 
194
    inline void sleepmillis(int s) {
 
195
        boost::xtime xt;
 
196
        boost::xtime_get(&xt, boost::TIME_UTC);
 
197
        xt.sec += ( s / 1000 );
 
198
        xt.nsec += ( s % 1000 ) * 1000000;
 
199
        if ( xt.nsec >= 1000000000 ) {
 
200
            xt.nsec -= 1000000000;
 
201
            xt.sec++;
 
202
        }        
 
203
        boost::thread::sleep(xt);
 
204
    }
 
205
    inline void sleepmicros(int s) {
 
206
        boost::xtime xt;
 
207
        boost::xtime_get(&xt, boost::TIME_UTC);
 
208
        xt.sec += ( s / 1000000 );
 
209
        xt.nsec += ( s % 1000000 ) * 1000;
 
210
        if ( xt.nsec >= 1000000000 ) {
 
211
            xt.nsec -= 1000000000;
 
212
            xt.sec++;
 
213
        }        
 
214
        boost::thread::sleep(xt);
 
215
    }
 
216
#else
 
217
    inline void sleepsecs(int s) {
 
218
        struct timespec t;
 
219
        t.tv_sec = s;
 
220
        t.tv_nsec = 0;
 
221
        if ( nanosleep( &t , 0 ) ){
 
222
            cout << "nanosleep failed" << endl;
 
223
        }
 
224
    }
 
225
    inline void sleepmicros(int s) {
 
226
        struct timespec t;
 
227
        t.tv_sec = (int)(s / 1000000);
 
228
        t.tv_nsec = s % 1000000;
 
229
        if ( nanosleep( &t , 0 ) ){
 
230
            cout << "nanosleep failed" << endl;
 
231
        }
 
232
    }
 
233
    inline void sleepmillis(int s) {
 
234
        sleepmicros( s * 1000 );
 
235
    }
 
236
#endif
 
237
 
 
238
// note this wraps
 
239
    inline int tdiff(unsigned told, unsigned tnew) {
 
240
        return WrappingInt::diff(tnew, told);
 
241
    }
 
242
    inline unsigned curTimeMillis() {
 
243
        boost::xtime xt;
 
244
        boost::xtime_get(&xt, boost::TIME_UTC);
 
245
        unsigned t = xt.nsec / 1000000;
 
246
        return (xt.sec & 0xfffff) * 1000 + t;
 
247
    }
 
248
 
 
249
    struct Date_t {
 
250
        // TODO: make signed (and look for related TODO's)
 
251
        unsigned long long millis;
 
252
        Date_t(): millis(0) {}
 
253
        Date_t(unsigned long long m): millis(m) {}
 
254
        operator unsigned long long&() { return millis; }
 
255
        operator const unsigned long long&() const { return millis; }
 
256
    };
 
257
 
 
258
    inline Date_t jsTime() {
 
259
        boost::xtime xt;
 
260
        boost::xtime_get(&xt, boost::TIME_UTC);
 
261
        unsigned long long t = xt.nsec / 1000000;
 
262
        return ((unsigned long long) xt.sec * 1000) + t;
 
263
    }
 
264
 
 
265
    inline unsigned long long curTimeMicros64() {
 
266
        boost::xtime xt;
 
267
        boost::xtime_get(&xt, boost::TIME_UTC);
 
268
        unsigned long long t = xt.nsec / 1000;
 
269
        return (((unsigned long long) xt.sec) * 1000000) + t;
 
270
    }
 
271
 
 
272
// measures up to 1024 seconds.  or, 512 seconds with tdiff that is...
 
273
    inline unsigned curTimeMicros() {
 
274
        boost::xtime xt;
 
275
        boost::xtime_get(&xt, boost::TIME_UTC);
 
276
        unsigned t = xt.nsec / 1000;
 
277
        unsigned secs = xt.sec % 1024;
 
278
        return secs*1000000 + t;
 
279
    }
 
280
    using namespace boost;
 
281
    typedef boost::mutex::scoped_lock boostlock;
 
282
    typedef boost::recursive_mutex::scoped_lock recursive_boostlock;
 
283
 
 
284
// simple scoped timer
 
285
    class Timer {
 
286
    public:
 
287
        Timer() {
 
288
            reset();
 
289
        }
 
290
        Timer( unsigned long long start ) {
 
291
            old = start;
 
292
        }
 
293
        int seconds(){
 
294
            return (int)(micros() / 1000000);
 
295
        }
 
296
        int millis() {
 
297
            return (long)(micros() / 1000);
 
298
        }
 
299
        unsigned long long micros() {
 
300
            unsigned long long n = curTimeMicros64();
 
301
            return n - old;
 
302
        }
 
303
        unsigned long long micros(unsigned long long & n) { // returns cur time in addition to timer result
 
304
            n = curTimeMicros64();
 
305
            return n - old;
 
306
        }
 
307
        unsigned long long startTime(){
 
308
            return old;
 
309
        }
 
310
        void reset() {
 
311
            old = curTimeMicros64();
 
312
        }
 
313
    private:
 
314
        unsigned long long old;
 
315
    };
 
316
 
 
317
    /*
 
318
 
 
319
    class DebugMutex : boost::noncopyable {
 
320
        friend class lock;
 
321
        boost::mutex m;
 
322
        int locked;
 
323
    public:
 
324
        DebugMutex() : locked(0); { }
 
325
        bool isLocked() { return locked; }
 
326
    };
 
327
 
 
328
    */
 
329
 
 
330
//typedef boostlock lock;
 
331
 
 
332
    inline bool startsWith(const char *str, const char *prefix) {
 
333
        unsigned l = strlen(prefix);
 
334
        if ( strlen(str) < l ) return false;
 
335
        return strncmp(str, prefix, l) == 0;
 
336
    }
 
337
 
 
338
    inline bool endsWith(const char *p, const char *suffix) {
 
339
        int a = strlen(p);
 
340
        int b = strlen(suffix);
 
341
        if ( b > a ) return false;
 
342
        return strcmp(p + a - b, suffix) == 0;
 
343
    }
 
344
 
 
345
} // namespace mongo
 
346
 
 
347
#include "boost/detail/endian.hpp"
 
348
 
 
349
namespace mongo {
 
350
 
 
351
    inline unsigned long swapEndian(unsigned long x) {
 
352
        return
 
353
            ((x & 0xff) << 24) |
 
354
            ((x & 0xff00) << 8) |
 
355
            ((x & 0xff0000) >> 8) |
 
356
            ((x & 0xff000000) >> 24);
 
357
    }
 
358
 
 
359
#if defined(BOOST_LITTLE_ENDIAN)
 
360
    inline unsigned long fixEndian(unsigned long x) {
 
361
        return x;
 
362
    }
 
363
#else
 
364
    inline unsigned long fixEndian(unsigned long x) {
 
365
        return swapEndian(x);
 
366
    }
 
367
#endif
 
368
 
 
369
    // Like strlen, but only scans up to n bytes.
 
370
    // Returns -1 if no '0' found.
 
371
    inline int strnlen( const char *s, int n ) {
 
372
        for( int i = 0; i < n; ++i )
 
373
            if ( !s[ i ] )
 
374
                return i;
 
375
        return -1;
 
376
    }
 
377
    
 
378
#if !defined(_WIN32)
 
379
    typedef int HANDLE;
 
380
    inline void strcpy_s(char *dst, unsigned len, const char *src) {
 
381
        strcpy(dst, src);
 
382
    }
 
383
#else
 
384
    typedef void *HANDLE;
 
385
#endif
 
386
    
 
387
    /* thread local "value" rather than a pointer
 
388
       good for things which have copy constructors (and the copy constructor is fast enough)
 
389
       e.g. 
 
390
         ThreadLocalValue<int> myint;
 
391
    */
 
392
    template<class T>
 
393
    class ThreadLocalValue {
 
394
    public:
 
395
        ThreadLocalValue( T def = 0 ) : _default( def ) { }
 
396
 
 
397
        T get() {
 
398
            T * val = _val.get();
 
399
            if ( val )
 
400
                return *val;
 
401
            return _default;
 
402
        }
 
403
 
 
404
        void set( const T& i ) {
 
405
            T *v = _val.get();
 
406
            if( v ) { 
 
407
                *v = i;
 
408
                return;
 
409
            }
 
410
            v = new T(i);
 
411
            _val.reset( v );
 
412
        }
 
413
 
 
414
    private:
 
415
        T _default;
 
416
        boost::thread_specific_ptr<T> _val;
 
417
    };
 
418
 
 
419
    class ProgressMeter {
 
420
    public:
 
421
        ProgressMeter( long long total , int secondsBetween = 3 , int checkInterval = 100 )
 
422
            : _total( total ) , _secondsBetween( secondsBetween ) , _checkInterval( checkInterval ) ,
 
423
              _done(0) , _hits(0) , _lastTime( (int) time(0) ){
 
424
        }
 
425
        
 
426
        bool hit( int n = 1 ){
 
427
            _done += n;
 
428
            _hits++;
 
429
            if ( _hits % _checkInterval )
 
430
                return false;
 
431
            
 
432
            int t = (int) time(0);
 
433
            if ( t - _lastTime < _secondsBetween )
 
434
                return false;
 
435
            
 
436
            if ( _total > 0 ){
 
437
                int per = (int)( ( (double)_done * 100.0 ) / (double)_total );
 
438
                cout << "\t\t" << _done << "/" << _total << "\t" << per << "%" << endl;
 
439
            }
 
440
            _lastTime = t;
 
441
            return true;
 
442
        }
 
443
 
 
444
        long long done(){
 
445
            return _done;
 
446
        }
 
447
        
 
448
        long long hits(){
 
449
            return _hits;
 
450
        }
 
451
 
 
452
    private:
 
453
        
 
454
        long long _total;
 
455
        int _secondsBetween;
 
456
        int _checkInterval;
 
457
 
 
458
        long long _done;
 
459
        long long _hits;
 
460
        int _lastTime;
 
461
    };
 
462
 
 
463
    class TicketHolder {
 
464
    public:
 
465
        TicketHolder( int num ){
 
466
            _outof = num;
 
467
            _num = num;
 
468
        }
 
469
        
 
470
        bool tryAcquire(){
 
471
            boostlock lk( _mutex );
 
472
            if ( _num <= 0 ){
 
473
                if ( _num < 0 ){
 
474
                    cerr << "DISASTER! in TicketHolder" << endl;
 
475
                }
 
476
                return false;
 
477
            }
 
478
            _num--;
 
479
            return true;
 
480
        }
 
481
        
 
482
        void release(){
 
483
            boostlock lk( _mutex );
 
484
            _num++;
 
485
        }
 
486
 
 
487
        void resize( int newSize ){
 
488
            boostlock lk( _mutex );            
 
489
            int used = _outof - _num;
 
490
            if ( used > newSize ){
 
491
                cout << "ERROR: can't resize since we're using (" << used << ") more than newSize(" << newSize << ")" << endl;
 
492
                return;
 
493
            }
 
494
            
 
495
            _outof = newSize;
 
496
            _num = _outof - used;
 
497
        }
 
498
 
 
499
        int available(){
 
500
            return _num;
 
501
        }
 
502
 
 
503
        int used(){
 
504
            return _outof - _num;
 
505
        }
 
506
 
 
507
    private:
 
508
        int _outof;
 
509
        int _num;
 
510
        boost::mutex _mutex;
 
511
    };
 
512
 
 
513
    class TicketHolderReleaser {
 
514
    public:
 
515
        TicketHolderReleaser( TicketHolder * holder ){
 
516
            _holder = holder;
 
517
        }
 
518
        
 
519
        ~TicketHolderReleaser(){
 
520
            _holder->release();
 
521
        }
 
522
    private:
 
523
        TicketHolder * _holder;
 
524
    };
 
525
 
 
526
} // namespace mongo