~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/mongo/db/clientcursor.cpp

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
   Cursor -- and its derived classes -- are our internal cursors.
23
23
*/
24
24
 
25
 
#include "pch.h"
26
 
#include "clientcursor.h"
27
 
#include "introspect.h"
 
25
#include "mongo/pch.h"
 
26
 
 
27
#include "mongo/db/clientcursor.h"
 
28
 
 
29
#include <string>
28
30
#include <time.h>
29
 
#include "db.h"
30
 
#include "commands.h"
31
 
#include "repl_block.h"
32
 
#include "../util/processinfo.h"
33
 
#include "../util/timer.h"
 
31
#include <vector>
 
32
 
34
33
#include "mongo/client/dbclientinterface.h"
 
34
#include "mongo/db/auth/action_set.h"
 
35
#include "mongo/db/auth/action_type.h"
 
36
#include "mongo/db/auth/authorization_manager.h"
 
37
#include "mongo/db/auth/privilege.h"
 
38
#include "mongo/db/commands.h"
 
39
#include "mongo/db/commands/server_status.h"
 
40
#include "mongo/db/db.h"
 
41
#include "mongo/db/introspect.h"
 
42
#include "mongo/db/jsobj.h"
 
43
#include "mongo/db/kill_current_op.h"
 
44
#include "mongo/db/pagefault.h"
 
45
#include "mongo/db/repl/rs.h"
 
46
#include "mongo/db/repl_block.h"
35
47
#include "mongo/db/scanandorder.h"
36
 
#include "pagefault.h"
37
 
#include "mongo/db/repl/rs.h"
 
48
#include "mongo/platform/random.h"
 
49
#include "mongo/util/processinfo.h"
 
50
#include "mongo/util/timer.h"
38
51
 
39
52
namespace mongo {
40
53
 
42
55
    boost::recursive_mutex& ClientCursor::ccmutex( *(new boost::recursive_mutex()) );
43
56
    long long ClientCursor::numberTimedOut = 0;
44
57
 
45
 
    void aboutToDeleteForSharding( const Database* db , const DiskLoc& dl ); // from s/d_logic.h
 
58
    void aboutToDeleteForSharding( const Database* db, const NamespaceDetails* nsd, const DiskLoc& dl ); // from s/d_logic.h
46
59
 
47
60
    /*static*/ void ClientCursor::assertNoCursors() {
48
61
        recursive_scoped_lock lock(ccmutex);
198
211
        Database *db = cc().database();
199
212
        CCByLoc& bl = db->ccByLoc;
200
213
        RARELY if ( bl.size() > 70 ) {
201
 
            log() << "perf warning: byLoc.size=" << bl.size() << " in aboutToDeleteBucket\n";
 
214
            log() << "perf warning: byLoc.size=" << bl.size() << " in aboutToDeleteBucket" << endl;
202
215
        }
203
216
        for ( CCByLoc::iterator i = bl.begin(); i != bl.end(); i++ )
204
217
            i->second->_c->aboutToDeleteBucket(b);
208
221
    }
209
222
 
210
223
    /* must call this on a delete so we clean up the cursors. */
211
 
    void ClientCursor::aboutToDelete(const DiskLoc& dl) {
 
224
    void ClientCursor::aboutToDelete(const NamespaceDetails* nsd, const DiskLoc& dl) {
212
225
        NoPageFaultsAllowed npfa;
213
226
 
214
227
        recursive_scoped_lock lock(ccmutex);
216
229
        Database *db = cc().database();
217
230
        verify(db);
218
231
 
219
 
        aboutToDeleteForSharding( db , dl );
 
232
        aboutToDeleteForSharding( db, nsd, dl );
220
233
 
221
234
        CCByLoc& bl = db->ccByLoc;
222
235
        CCByLoc::iterator j = bl.lower_bound(ByLocKey::min(dl));
290
303
            cc->updateLocation();
291
304
        }
292
305
    }
293
 
    void aboutToDelete(const DiskLoc& dl) { ClientCursor::aboutToDelete(dl); }
294
306
 
295
307
    void ClientCursor::LockedIterator::deleteAndAdvance() {
296
308
        ClientCursor *cc = current();
423
435
        return b.obj();
424
436
    }
425
437
    
 
438
    BSONObj ClientCursor::extractKey( const KeyPattern& usingKeyPattern ) const {
 
439
        KeyPattern currentIndex( _c->indexKeyPattern() );
 
440
        if ( usingKeyPattern.isCoveredBy( currentIndex ) && ! currentIndex.isSpecial() ){
 
441
            BSONObj currKey = _c->currKey();
 
442
            BSONObj prettyKey = currKey.replaceFieldNames( currentIndex.toBSON() );
 
443
            return usingKeyPattern.extractSingleKey( prettyKey );
 
444
        }
 
445
        return usingKeyPattern.extractSingleKey( _c->current() );
 
446
    }
 
447
 
426
448
    void ClientCursor::fillQueryResultFromObj( BufBuilder &b, const MatchDetails* details ) const {
427
449
        const Projection::KeyOnly *keyFieldsOnly = c()->keyFieldsOnly();
428
450
        if ( keyFieldsOnly ) {
445
467
        _c->prepareToYield();
446
468
        DiskLoc cl = _c->refLoc();
447
469
        if ( lastLoc() == cl ) {
448
 
            //log() << "info: lastloc==curloc " << ns << '\n';
 
470
            //log() << "info: lastloc==curloc " << ns << endl;
449
471
        }
450
472
        else {
451
473
            recursive_scoped_lock lock(ccmutex);
546
568
            dbtempreleasecond unlock;
547
569
            if ( unlock.unlocked() ) {
548
570
                if ( haveReadLock ) {
549
 
                    // don't sleep with a read lock
 
571
                    // This sleep helps reader threads yield to writer threads.
 
572
                    // Without this, the underlying reader/writer lock implementations
 
573
                    // are not sufficiently writer-greedy.
 
574
                    sleepmicros(1);
550
575
                }
551
576
                else {
552
577
                    if ( micros == -1 )
636
661
        return ClientCursor::recoverFromYield( data );
637
662
    }
638
663
 
639
 
    // See SERVER-5726.
640
 
    long long ctmLast = 0; // so we don't have to do find() which is a little slow very often.
 
664
    namespace {
 
665
        // so we don't have to do find() which is a little slow very often.
 
666
        long long cursorGenTSLast = 0;
 
667
        PseudoRandom* cursorGenRandom = NULL;
 
668
    }
 
669
 
641
670
    long long ClientCursor::allocCursorId_inlock() {
642
 
        long long ctm = curTimeMillis64();
643
 
        dassert( ctm );
 
671
        // It is important that cursor IDs not be reused within a short period of time.
 
672
 
 
673
        if ( ! cursorGenRandom ) {
 
674
            scoped_ptr<SecureRandom> sr( SecureRandom::create() );
 
675
            cursorGenRandom = new PseudoRandom( sr->nextInt64() );
 
676
        }
 
677
 
 
678
        const long long ts = Listener::getElapsedTimeMillis();
 
679
 
644
680
        long long x;
 
681
 
645
682
        while ( 1 ) {
646
 
            x = (((long long)rand()) << 32);
647
 
            x = x ^ ctm;
648
 
            if ( ctm != ctmLast || ClientCursor::find_inlock(x, false) == 0 )
 
683
            x = ts << 32;
 
684
            x |= cursorGenRandom->nextInt32();
 
685
 
 
686
            if ( x == 0 )
 
687
                continue;
 
688
 
 
689
            if ( x < 0 )
 
690
                x *= -1;
 
691
 
 
692
            if ( ts != cursorGenTSLast || ClientCursor::find_inlock(x, false) == 0 )
649
693
                break;
650
694
        }
651
 
        ctmLast = ctm;
 
695
 
 
696
        cursorGenTSLast = ts;
 
697
 
652
698
        return x;
653
699
    }
654
700
 
701
747
            help << " example: { cursorInfo : 1 }";
702
748
        }
703
749
        virtual LockType locktype() const { return NONE; }
 
750
        virtual void addRequiredPrivileges(const std::string& dbname,
 
751
                                           const BSONObj& cmdObj,
 
752
                                           std::vector<Privilege>* out) {
 
753
            ActionSet actions;
 
754
            actions.addAction(ActionType::cursorInfo);
 
755
            out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_NAME, actions));
 
756
        }
704
757
        bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) {
705
758
            ClientCursor::appendStats( result );
706
759
            return true;
707
760
        }
708
761
    } cmdCursorInfo;
709
762
 
 
763
    class CursorServerStats : public ServerStatusSection {
 
764
    public:
 
765
 
 
766
        CursorServerStats() : ServerStatusSection( "cursors" ){}
 
767
        virtual bool includeByDefault() const { return true; }
 
768
 
 
769
        BSONObj generateSection(const BSONElement& configElement) const {
 
770
            BSONObjBuilder b;
 
771
            ClientCursor::appendStats( b );
 
772
            return b.obj();
 
773
        }
 
774
 
 
775
    } cursorServerStats;
 
776
 
710
777
    struct Mem { 
711
778
        Mem() { res = virt = mapped = 0; }
712
779
        long long res;
741
808
                    else {
742
809
                        log() << " mapped:" << totalMapped;
743
810
                    }
744
 
                    log() << " connections:" << connTicketHolder.used();
 
811
                    log() << " connections:" << Listener::globalTicketHolder.used();
745
812
                    if (theReplSet) {
746
813
                        log() << " replication threads:" << 
747
814
                            ReplSetImpl::replWriterThreadCount + 
783
850
        }
784
851
    }
785
852
 
786
 
    bool ClientCursor::erase( CursorId id ) {
787
 
        recursive_scoped_lock lock( ccmutex );
788
 
        ClientCursor *cursor = find_inlock( id );
789
 
        if ( ! cursor )
790
 
            return false;
791
 
 
792
 
        if ( ! cc().getAuthenticationInfo()->isAuthorizedReads( nsToDatabase( cursor->ns() ) ) )
793
 
            return false;
794
 
 
 
853
    bool ClientCursor::_erase_inlock(ClientCursor* cursor) {
795
854
        // Must not have an active ClientCursor::Pin.
796
855
        massert( 16089,
797
 
                str::stream() << "Cannot kill active cursor " << id,
 
856
                str::stream() << "Cannot kill active cursor " << cursor->cursorid(),
798
857
                cursor->_pinValue < 100 );
799
 
        
 
858
 
800
859
        delete cursor;
801
860
        return true;
802
861
    }
803
862
 
 
863
    bool ClientCursor::erase(CursorId id) {
 
864
        recursive_scoped_lock lock(ccmutex);
 
865
        ClientCursor* cursor = find_inlock(id);
 
866
        if (!cursor) {
 
867
            return false;
 
868
        }
 
869
 
 
870
        return _erase_inlock(cursor);
 
871
    }
 
872
 
 
873
    bool ClientCursor::eraseIfAuthorized(CursorId id) {
 
874
        std::string ns;
 
875
        {
 
876
            recursive_scoped_lock lock(ccmutex);
 
877
            ClientCursor* cursor = find_inlock(id);
 
878
            if (!cursor) {
 
879
                return false;
 
880
            }
 
881
            ns = cursor->ns();
 
882
        }
 
883
 
 
884
        // Can't be in a lock when checking authorization
 
885
        if (!cc().getAuthorizationManager()->checkAuthorization(ns, ActionType::killCursors)) {
 
886
            return false;
 
887
        }
 
888
 
 
889
        // It is safe to lookup the cursor again after temporarily releasing the mutex because
 
890
        // of 2 invariants: that the cursor ID won't be re-used in a short period of time, and that
 
891
        // the namespace associated with a cursor cannot change.
 
892
        recursive_scoped_lock lock(ccmutex);
 
893
        ClientCursor* cursor = find_inlock(id);
 
894
        if (!cursor) {
 
895
            // Cursor was deleted in another thread since we found it earlier in this function.
 
896
            return false;
 
897
        }
 
898
        if (cursor->ns() != ns) {
 
899
            warning() << "Cursor namespace changed. Previous ns: " << ns << ", current ns: "
 
900
                    << cursor->ns() << endl;
 
901
            return false;
 
902
        }
 
903
 
 
904
        return _erase_inlock(cursor);
 
905
    }
 
906
 
804
907
    int ClientCursor::erase(int n, long long *ids) {
805
908
        int found = 0;
806
909
        for ( int i = 0; i < n; i++ ) {
807
 
            if ( erase(ids[i]) )
808
 
                found++;
809
 
 
810
 
            if ( inShutdown() )
811
 
                break;
812
 
        }
813
 
        return found;
814
 
 
 
910
            if ( erase(ids[i]))
 
911
                found++;
 
912
 
 
913
            if ( inShutdown() )
 
914
                break;
 
915
        }
 
916
        return found;
 
917
    }
 
918
 
 
919
    int ClientCursor::eraseIfAuthorized(int n, long long *ids) {
 
920
        int found = 0;
 
921
        for ( int i = 0; i < n; i++ ) {
 
922
            if ( eraseIfAuthorized(ids[i]))
 
923
                found++;
 
924
 
 
925
            if ( inShutdown() )
 
926
                break;
 
927
        }
 
928
        return found;
815
929
    }
816
930
 
817
931
    ClientCursor::YieldLock::YieldLock( ptr<ClientCursor> cc )