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

« back to all changes in this revision

Viewing changes to src/mongo/db/pdfile.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:
23
23
_ disallow system* manipulations from the database.
24
24
*/
25
25
 
26
 
#include "pch.h"
27
 
#include "pdfile.h"
28
 
#include "mongo/db/pdfile_private.h"
29
 
#include "db.h"
30
 
#include "../util/mmap.h"
31
 
#include "../util/hashtab.h"
32
 
#include "../util/file_allocator.h"
33
 
#include "../util/processinfo.h"
34
 
#include "../util/file.h"
35
 
#include "btree.h"
36
 
#include "btreebuilder.h"
 
26
#include "mongo/pch.h"
 
27
 
 
28
#include "mongo/db/pdfile.h"
 
29
 
37
30
#include <algorithm>
 
31
#include <boost/filesystem/operations.hpp>
 
32
#include <boost/optional/optional.hpp>
38
33
#include <list>
39
 
#include "repl.h"
40
 
#include "dbhelpers.h"
41
 
#include "namespace-inl.h"
42
 
#include "extsort.h"
43
 
#include "curop-inl.h"
44
 
#include "background.h"
45
 
#include "compact.h"
46
 
#include "ops/delete.h"
47
 
#include "instance.h"
48
 
#include "replutil.h"
49
 
#include "memconcept.h"
 
34
 
 
35
#include "mongo/base/counter.h"
 
36
#include "mongo/db/auth/auth_index_d.h"
 
37
#include "mongo/db/auth/authorization_manager.h"
 
38
#include "mongo/db/pdfile_private.h"
 
39
#include "mongo/db/background.h"
 
40
#include "mongo/db/btree.h"
 
41
#include "mongo/db/commands/server_status.h"
 
42
#include "mongo/db/curop-inl.h"
 
43
#include "mongo/db/db.h"
 
44
#include "mongo/db/dbhelpers.h"
 
45
#include "mongo/db/extsort.h"
 
46
#include "mongo/db/index_update.h"
 
47
#include "mongo/db/instance.h"
 
48
#include "mongo/db/kill_current_op.h"
50
49
#include "mongo/db/lasterror.h"
51
 
#include "mongo/db/index_update.h"
52
 
 
53
 
#include <boost/filesystem/operations.hpp>
 
50
#include "mongo/db/memconcept.h"
 
51
#include "mongo/db/namespace-inl.h"
 
52
#include "mongo/db/namespacestring.h"
 
53
#include "mongo/db/ops/delete.h"
 
54
#include "mongo/db/repl.h"
 
55
#include "mongo/db/replutil.h"
 
56
#include "mongo/db/sort_phase_one.h"
 
57
#include "mongo/util/file.h"
 
58
#include "mongo/util/file_allocator.h"
 
59
#include "mongo/util/hashtab.h"
 
60
#include "mongo/util/mmap.h"
 
61
#include "mongo/util/processinfo.h"
 
62
#include "mongo/db/stats/timer_stats.h"
 
63
#include "mongo/db/stats/counters.h"
54
64
 
55
65
namespace mongo {
56
66
 
57
67
    BOOST_STATIC_ASSERT( sizeof(Extent)-4 == 48+128 );
58
68
    BOOST_STATIC_ASSERT( sizeof(DataFileHeader)-4 == 8192 );
59
69
 
60
 
    void printMemInfo( const char * where ) {
61
 
        cout << "mem info: ";
62
 
        if ( where )
63
 
            cout << where << " ";
64
 
        ProcessInfo pi;
65
 
        if ( ! pi.supported() ) {
66
 
            cout << " not supported" << endl;
67
 
            return;
68
 
        }
69
 
 
70
 
        cout << "vsize: " << pi.getVirtualMemorySize() << " resident: " << pi.getResidentSize() << " mapped: " << ( MemoryMappedFile::totalMappedLength() / ( 1024 * 1024 ) ) << endl;
71
 
    }
 
70
    //The oplog entries inserted
 
71
    static TimerStats oplogInsertStats;
 
72
    static ServerStatusMetricField<TimerStats> displayInsertedOplogEntries(
 
73
                                                    "repl.oplog.insert",
 
74
                                                    &oplogInsertStats );
 
75
    static Counter64 oplogInsertBytesStats;
 
76
    static ServerStatusMetricField<Counter64> displayInsertedOplogEntryBytes(
 
77
                                                    "repl.oplog.insertBytes",
 
78
                                                    &oplogInsertBytesStats );
72
79
 
73
80
    bool isValidNS( const StringData& ns ) {
74
81
        // TODO: should check for invalid characters
75
82
 
76
 
        const char * x = strchr( ns.data() , '.' );
77
 
        if ( ! x )
78
 
            return false;
79
 
 
80
 
        x++;
81
 
        return *x > 0;
 
83
        size_t idx = ns.find( '.' );
 
84
        if ( idx == string::npos )
 
85
            return false;
 
86
 
 
87
        if ( idx == ns.size() - 1 )
 
88
            return false;
 
89
 
 
90
        return true;
82
91
    }
83
92
 
84
93
    // TODO SERVER-4328
120
129
    BackgroundOperation::BackgroundOperation(const char *ns) : _ns(ns) {
121
130
        SimpleMutex::scoped_lock lk(m);
122
131
        dbsInProg[_ns.db]++;
123
 
        verify( nsInProg.count(_ns.ns()) == 0 );
124
132
        nsInProg.insert(_ns.ns());
125
133
    }
126
134
 
167
175
        if ( ( strstr( ns, ".system." ) == 0 || legalClientSystemNS( ns , false ) ) &&
168
176
                strstr( ns, FREELIST_NS ) == 0 ) {
169
177
            LOG( 1 ) << "adding _id index for collection " << ns << endl;
170
 
            ensureHaveIdIndex( ns );
 
178
            ensureHaveIdIndex( ns, false );
 
179
        }
 
180
    }
 
181
 
 
182
    static void _ensureSystemIndexes(const char* ns) {
 
183
        NamespaceString nsstring(ns);
 
184
        if (StringData(nsstring.coll).substr(0, 7) == "system.") {
 
185
            authindex::createSystemIndexes(nsstring);
171
186
        }
172
187
    }
173
188
 
229
244
    }
230
245
 
231
246
    void checkConfigNS(const char *ns) {
232
 
        if ( cmdLine.configsvr && 
233
 
             !( str::startsWith( ns, "config." ) || str::startsWith( ns, "admin." ) ) ) { 
 
247
        if ( cmdLine.configsvr &&
 
248
             !( str::startsWith( ns, "config." ) ||
 
249
                str::startsWith( ns, "local." ) ||
 
250
                str::startsWith( ns, "admin." ) ) ) {
234
251
            uasserted(14037, "can't create user databases on a --configsvr instance");
235
252
        }
236
253
    }
250
267
            BSONElement e = options.getField("size");
251
268
            if ( e.isNumber() ) {
252
269
                size = e.numberLong();
253
 
                size += 256;
 
270
                uassert( 10083 , "create collection invalid size spec", size > 0 );
 
271
 
 
272
                size += 0xff;
254
273
                size &= 0xffffffffffffff00LL;
 
274
                if ( size < Extent::minSize() )
 
275
                    size = Extent::minSize();
255
276
            }
256
277
        }
257
278
 
258
 
        uassert( 10083 , "create collection invalid size spec", size > 0 );
259
 
 
260
279
        bool newCapped = false;
261
280
        long long mx = 0;
262
281
        if( options["capped"].trueValue() ) {
264
283
            BSONElement e = options.getField("max");
265
284
            if ( e.isNumber() ) {
266
285
                mx = e.numberLong();
 
286
                uassert( 16495,
 
287
                         "max in a capped collection has to be < 2^31 or not set",
 
288
                         NamespaceDetails::validMaxCappedDocs(&mx) );
267
289
            }
268
290
        }
269
291
 
319
341
        // capped ones in local w/o autoIndexID (reason for the exception is for the oplog and
320
342
        //  non-replicated capped colls)
321
343
        if( options.hasField( "autoIndexId" ) ||
322
 
            (newCapped && str::equals( nsToDatabase( ns ).c_str() ,  "local" )) ) {
 
344
            (newCapped && nsToDatabase( ns ) == "local" ) ) {
323
345
            ensure = options.getField( "autoIndexId" ).trueValue();
324
346
        }
325
347
 
329
351
            else
330
352
                ensureIdIndexForNewNs( ns );
331
353
        }
332
 
        
 
354
 
 
355
        _ensureSystemIndexes(ns);
 
356
 
333
357
        if ( mx > 0 )
334
358
            d->setMaxCappedDocs( mx );
335
359
 
351
375
    bool userCreateNS(const char *ns, BSONObj options, string& err, bool logForReplication, bool *deferIdIndex) {
352
376
        const char *coll = strchr( ns, '.' ) + 1;
353
377
        massert( 10356 ,  str::stream() << "invalid ns: " << ns , NamespaceString::validCollectionName(ns));
354
 
        char cl[ 256 ];
355
 
        nsToDatabase( ns, cl );
356
378
        bool ok = _userCreateNS(ns, options, err, deferIdIndex);
357
379
        if ( logForReplication && ok ) {
358
380
            if ( options.getField( "create" ).eoo() ) {
361
383
                b.appendElements( options );
362
384
                options = b.obj();
363
385
            }
364
 
            string logNs = string( cl ) + ".$cmd";
 
386
            string logNs = nsToDatabase(ns) + ".$cmd";
365
387
            logOp("c", logNs.c_str(), options);
366
388
        }
367
389
        return ok;
523
545
                verify( loops < 10000 );
524
546
                out() << "warning: loops=" << loops << " fileno:" << fileNo << ' ' << ns << '\n';
525
547
            }
526
 
            log() << "newExtent: " << ns << " file " << fileNo << " full, adding a new file\n";
 
548
            log() << "newExtent: " << ns << " file " << fileNo << " full, adding a new file" << endl;
527
549
            return cc().database()->addAFile( 0, true )->createExtent(ns, approxSize, newCapped, loops+1);
528
550
        }
529
551
        int offset = header()->unused.getOfs();
544
566
 
545
567
    Extent* DataFileMgr::allocFromFreeList(const char *ns, int approxSize, bool capped) {
546
568
        string s = cc().database()->name + FREELIST_NS;
547
 
        NamespaceDetails *f = nsdetails(s.c_str());
 
569
        NamespaceDetails *f = nsdetails(s);
548
570
        if( f ) {
549
571
            int low, high;
550
572
            if( capped ) {
620
642
                    f->lastExtent.writing() = e->xprev;
621
643
 
622
644
                // use it
623
 
                OCCASIONALLY if( n > 512 ) log() << "warning: newExtent " << n << " scanned\n";
 
645
                OCCASIONALLY if( n > 512 ) log() << "warning: newExtent " << n << " scanned" << endl;
624
646
                DiskLoc emptyLoc = e->reuse(ns, capped);
625
647
                addNewExtentToNamespace(ns, e, e->myLoc, emptyLoc, capped);
626
648
                return e;
675
697
        getEmptyLoc(nsname, myLoc, length, capped, emptyLoc, delRecLength);
676
698
 
677
699
        // todo: some dup code here and below in Extent::init
678
 
        DeletedRecord *empty = DataFileMgr::makeDeletedRecord(emptyLoc, delRecLength);
679
 
        empty = getDur().writing(empty);
 
700
        DeletedRecord* empty = getDur().writing(DataFileMgr::getDeletedRecord(emptyLoc));
680
701
        empty->lengthWithHeaders() = delRecLength;
681
702
        empty->extentOfs() = myLoc.getOfs();
682
703
        empty->nextDeleted().Null();
683
 
 
684
704
        return emptyLoc;
685
705
    }
686
706
 
699
719
        int delRecLength;
700
720
        getEmptyLoc(nsname, myLoc, _length, capped, emptyLoc, delRecLength);
701
721
 
702
 
        DeletedRecord *empty = getDur().writing( DataFileMgr::makeDeletedRecord(emptyLoc, delRecLength) );
 
722
        DeletedRecord* empty = getDur().writing(DataFileMgr::getDeletedRecord(emptyLoc));
703
723
        empty->lengthWithHeaders() = delRecLength;
704
724
        empty->extentOfs() = myLoc.getOfs();
705
 
 
 
725
        empty->nextDeleted().Null();
706
726
        return emptyLoc;
707
727
    }
708
728
 
709
 
        bool Extent::validates(const DiskLoc diskLoc, BSONArrayBuilder* errors) {
710
 
            bool extentOk = true;
711
 
            if (magic != extentSignature) {
712
 
                if (errors) {
713
 
                    StringBuilder sb;
714
 
                    sb << "bad extent signature " << toHex(&magic, 4)
715
 
                       << " in extent " << diskLoc.toString();
716
 
                    *errors << sb.str();
717
 
                }
718
 
                extentOk = false;
719
 
            }
720
 
            if (myLoc != diskLoc) {
721
 
                if (errors) {
722
 
                    StringBuilder sb;
723
 
                    sb << "extent " << diskLoc.toString()
724
 
                       << " self-pointer is " << myLoc.toString();
725
 
                    *errors << sb.str();
726
 
                }
727
 
                extentOk = false;
728
 
            }
729
 
            if (firstRecord.isNull() != lastRecord.isNull()) {
730
 
                if (errors) {
731
 
                    StringBuilder sb;
732
 
                    if (firstRecord.isNull()) {
733
 
                        sb << "in extent " << diskLoc.toString()
734
 
                           << ", firstRecord is null but lastRecord is "
735
 
                           << lastRecord.toString();
736
 
                    }
737
 
                    else {
738
 
                        sb << "in extent " << diskLoc.toString()
739
 
                           << ", firstRecord is " << firstRecord.toString()
740
 
                           << " but lastRecord is null";
741
 
                    }
742
 
                    *errors << sb.str();
743
 
                }
744
 
                extentOk = false;
745
 
            }
746
 
            if (length < minSize()) {
747
 
                if (errors) {
748
 
                    StringBuilder sb;
749
 
                    sb << "length of extent " << diskLoc.toString()
750
 
                       << " is " << length
751
 
                       << ", which is less than minimum length of " << minSize();
752
 
                    *errors << sb.str();
753
 
                }
754
 
                extentOk = false;
755
 
            }
756
 
            return extentOk;
757
 
        }
758
 
 
759
 
    /*
760
 
      Record* Extent::newRecord(int len) {
761
 
      if( firstEmptyRegion.isNull() )8
762
 
      return 0;
763
 
 
764
 
      verify(len > 0);
765
 
      int newRecSize = len + Record::HeaderSize;
766
 
      DiskLoc newRecordLoc = firstEmptyRegion;
767
 
      Record *r = getRecord(newRecordLoc);
768
 
      int left = r->netLength() - len;
769
 
      if( left < 0 ) {
770
 
      //
771
 
      firstEmptyRegion.Null();
772
 
      return 0;
773
 
      }
774
 
 
775
 
      DiskLoc nextEmpty = r->next.getNextEmpty(firstEmptyRegion);
776
 
      r->lengthWithHeaders = newRecSize;
777
 
      r->next.markAsFirstOrLastInExtent(this); // we're now last in the extent
778
 
      if( !lastRecord.isNull() ) {
779
 
      verify(getRecord(lastRecord)->next.lastInExtent()); // it was the last one
780
 
      getRecord(lastRecord)->next.set(newRecordLoc); // until now
781
 
      r->prev.set(lastRecord);
782
 
      }
783
 
      else {
784
 
      r->prev.markAsFirstOrLastInExtent(this); // we are the first in the extent
785
 
      verify( firstRecord.isNull() );
786
 
      firstRecord = newRecordLoc;
787
 
      }
788
 
      lastRecord = newRecordLoc;
789
 
 
790
 
      if( left < Record::HeaderSize + 32 ) {
791
 
      firstEmptyRegion.Null();
792
 
      }
793
 
      else {
794
 
      firstEmptyRegion.inc(newRecSize);
795
 
      Record *empty = getRecord(firstEmptyRegion);
796
 
      empty->next.set(nextEmpty); // not for empty records, unless in-use records, next and prev can be null.
797
 
      empty->prev.Null();
798
 
      empty->lengthWithHeaders = left;
799
 
      }
800
 
 
801
 
      return r;
802
 
      }
803
 
    */
 
729
    bool Extent::validates(const DiskLoc diskLoc, BSONArrayBuilder* errors) {
 
730
        bool extentOk = true;
 
731
        if (magic != extentSignature) {
 
732
            if (errors) {
 
733
                StringBuilder sb;
 
734
                sb << "bad extent signature " << toHex(&magic, 4)
 
735
                    << " in extent " << diskLoc.toString();
 
736
                *errors << sb.str();
 
737
            }
 
738
            extentOk = false;
 
739
        }
 
740
        if (myLoc != diskLoc) {
 
741
            if (errors) {
 
742
                StringBuilder sb;
 
743
                sb << "extent " << diskLoc.toString()
 
744
                    << " self-pointer is " << myLoc.toString();
 
745
                *errors << sb.str();
 
746
            }
 
747
            extentOk = false;
 
748
        }
 
749
        if (firstRecord.isNull() != lastRecord.isNull()) {
 
750
            if (errors) {
 
751
                StringBuilder sb;
 
752
                if (firstRecord.isNull()) {
 
753
                    sb << "in extent " << diskLoc.toString()
 
754
                        << ", firstRecord is null but lastRecord is "
 
755
                        << lastRecord.toString();
 
756
                }
 
757
                else {
 
758
                    sb << "in extent " << diskLoc.toString()
 
759
                        << ", firstRecord is " << firstRecord.toString()
 
760
                        << " but lastRecord is null";
 
761
                }
 
762
                *errors << sb.str();
 
763
            }
 
764
            extentOk = false;
 
765
        }
 
766
        if (length < minSize()) {
 
767
            if (errors) {
 
768
                StringBuilder sb;
 
769
                sb << "length of extent " << diskLoc.toString()
 
770
                    << " is " << length
 
771
                    << ", which is less than minimum length of " << minSize();
 
772
                *errors << sb.str();
 
773
            }
 
774
            extentOk = false;
 
775
        }
 
776
        return extentOk;
 
777
    }
 
778
 
 
779
/*
 
780
    Record* Extent::newRecord(int len) {
 
781
        if( firstEmptyRegion.isNull() )8
 
782
            return 0;
 
783
 
 
784
        verify(len > 0);
 
785
        int newRecSize = len + Record::HeaderSize;
 
786
        DiskLoc newRecordLoc = firstEmptyRegion;
 
787
        Record *r = getRecord(newRecordLoc);
 
788
        int left = r->netLength() - len;
 
789
        if( left < 0 ) {
 
790
            //
 
791
            firstEmptyRegion.Null();
 
792
            return 0;
 
793
        }
 
794
 
 
795
        DiskLoc nextEmpty = r->next.getNextEmpty(firstEmptyRegion);
 
796
        r->lengthWithHeaders = newRecSize;
 
797
        r->next.markAsFirstOrLastInExtent(this); // we're now last in the extent
 
798
        if( !lastRecord.isNull() ) {
 
799
            verify(getRecord(lastRecord)->next.lastInExtent()); // it was the last one
 
800
            getRecord(lastRecord)->next.set(newRecordLoc); // until now
 
801
            r->prev.set(lastRecord);
 
802
        }
 
803
        else {
 
804
            r->prev.markAsFirstOrLastInExtent(this); // we are the first in the extent
 
805
            verify( firstRecord.isNull() );
 
806
            firstRecord = newRecordLoc;
 
807
        }
 
808
        lastRecord = newRecordLoc;
 
809
 
 
810
        if( left < Record::HeaderSize + 32 ) {
 
811
            firstEmptyRegion.Null();
 
812
        }
 
813
        else {
 
814
            firstEmptyRegion.inc(newRecSize);
 
815
            Record *empty = getRecord(firstEmptyRegion);
 
816
            empty->next.set(nextEmpty); // not for empty records, unless in-use records, next and prev can be null.
 
817
            empty->prev.Null();
 
818
            empty->lengthWithHeaders = left;
 
819
        }
 
820
 
 
821
        return r;
 
822
    }
 
823
*/
804
824
 
805
825
    int Extent::maxSize() {
806
826
        int maxExtentSize = 0x7ff00000;
812
832
 
813
833
    /*---------------------------------------------------------------------*/
814
834
 
815
 
    shared_ptr<Cursor> DataFileMgr::findAll(const char *ns, const DiskLoc &startLoc) {
 
835
    DataFileMgr::DataFileMgr() : _precalcedMutex("PrecalcedMutex"), _precalced(NULL) {
 
836
    }
 
837
 
 
838
    SortPhaseOne* DataFileMgr::getPrecalced() const {
 
839
        return _precalced;
 
840
    }
 
841
 
 
842
    void DataFileMgr::setPrecalced(SortPhaseOne* precalced) {
 
843
        _precalced = precalced;
 
844
    }
 
845
 
 
846
    shared_ptr<Cursor> DataFileMgr::findAll(const StringData& ns, const DiskLoc &startLoc) {
816
847
        NamespaceDetails * d = nsdetails( ns );
817
848
        if ( ! d )
818
849
            return shared_ptr<Cursor>(new BasicCursor(DiskLoc()));
890
921
    void printFreeList() {
891
922
        string s = cc().database()->name + FREELIST_NS;
892
923
        log() << "dump freelist " << s << endl;
893
 
        NamespaceDetails *freeExtents = nsdetails(s.c_str());
 
924
        NamespaceDetails *freeExtents = nsdetails(s);
894
925
        if( freeExtents == 0 ) {
895
926
            log() << "  freeExtents==0" << endl;
896
927
            return;
920
951
        }
921
952
 
922
953
        string s = cc().database()->name + FREELIST_NS;
923
 
        NamespaceDetails *freeExtents = nsdetails(s.c_str());
 
954
        NamespaceDetails *freeExtents = nsdetails(s);
924
955
        if( freeExtents == 0 ) {
925
956
            string err;
926
957
            _userCreateNS(s.c_str(), BSONObj(), err, 0); // todo: this actually allocates an extent, which is bad!
927
 
            freeExtents = nsdetails(s.c_str());
 
958
            freeExtents = nsdetails(s);
928
959
            massert( 10361 , "can't create .$freelist", freeExtents);
929
960
        }
930
961
        if( freeExtents->firstExtent.isNull() ) {
944
975
 
945
976
    /* drop a collection/namespace */
946
977
    void dropNS(const string& nsToDrop) {
947
 
        NamespaceDetails* d = nsdetails(nsToDrop.c_str());
 
978
        NamespaceDetails* d = nsdetails(nsToDrop);
948
979
        uassert( 10086 ,  (string)"ns not found: " + nsToDrop , d );
949
980
 
950
981
        BackgroundOperation::assertNoBgOpInProgForNs(nsToDrop.c_str());
952
983
        NamespaceString s(nsToDrop);
953
984
        verify( s.db == cc().database()->name );
954
985
        if( s.isSystem() ) {
955
 
            if( s.coll == "system.profile" )
956
 
                uassert( 10087 ,  "turn off profiling before dropping system.profile collection", cc().database()->profile == 0 );
957
 
            else
 
986
            if( s.coll == "system.profile" ) {
 
987
                uassert( 10087,
 
988
                         "turn off profiling before dropping system.profile collection",
 
989
                         cc().database()->getProfilingLevel() == 0 );
 
990
            }
 
991
            else {
958
992
                uasserted( 12502, "can't drop system ns" );
 
993
            }
959
994
        }
960
995
 
961
996
        {
979
1014
 
980
1015
    void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ) {
981
1016
        LOG(1) << "dropCollection: " << name << endl;
982
 
        NamespaceDetails *d = nsdetails(name.c_str());
 
1017
        NamespaceDetails *d = nsdetails(name);
983
1018
        if( d == 0 )
984
1019
            return;
985
1020
 
1001
1036
        result.append("ns", name.c_str());
1002
1037
        ClientCursor::invalidate(name.c_str());
1003
1038
        Top::global.collectionDropped( name );
1004
 
        NamespaceDetailsTransient::eraseForPrefix( name.c_str() );
 
1039
        NamespaceDetailsTransient::eraseCollection( name );
1005
1040
        dropNS(name);
1006
1041
    }
1007
1042
 
1042
1077
                s->nrecords--;
1043
1078
            }
1044
1079
 
1045
 
            if ( strstr(ns, ".system.indexes") ) {
 
1080
            if (NamespaceString(ns).coll ==  "system.indexes") {
1046
1081
                /* temp: if in system.indexes, don't reuse, and zero out: we want to be
1047
1082
                   careful until validated more, as IndexDetails has pointers
1048
1083
                   to this disk location.  so an incorrectly done remove would cause
1062
1097
    }
1063
1098
 
1064
1099
    void DataFileMgr::deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK, bool noWarn, bool doLog ) {
 
1100
        deleteRecord( nsdetails(ns), ns, todelete, dl, cappedOK, noWarn, doLog );
 
1101
    }
 
1102
 
 
1103
    void DataFileMgr::deleteRecord(NamespaceDetails* d, const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK, bool noWarn, bool doLog ) {
1065
1104
        dassert( todelete == dl.rec() );
1066
1105
 
1067
 
        NamespaceDetails* d = nsdetails(ns);
1068
1106
        if ( d->isCapped() && !cappedOK ) {
1069
1107
            out() << "failing remove on a capped ns " << ns << endl;
1070
1108
            uassert( 10089 ,  "can't remove from a capped collection" , 0 );
1080
1118
        }
1081
1119
 
1082
1120
        /* check if any cursors point to us.  if so, advance them. */
1083
 
        ClientCursor::aboutToDelete(dl);
 
1121
        ClientCursor::aboutToDelete(d, dl);
1084
1122
 
1085
1123
        unindexRecord(d, todelete, dl, noWarn);
1086
1124
 
1092
1130
        }
1093
1131
    }
1094
1132
 
 
1133
    Counter64 moveCounter;
 
1134
    ServerStatusMetricField<Counter64> moveCounterDisplay( "record.moves", &moveCounter );
1095
1135
 
1096
1136
    /** Note: if the object shrinks a lot, we don't free up space, we leave extra at end of the record.
1097
1137
     */
1122
1162
            objNew = b.obj();
1123
1163
        }
1124
1164
 
 
1165
        NamespaceString nsstring(ns);
 
1166
        if (nsstring.coll == "system.users") {
 
1167
            uassertStatusOK(AuthorizationManager::checkValidPrivilegeDocument(nsstring.db, objNew));
 
1168
        }
 
1169
 
1125
1170
        /* duplicate key check. we descend the btree twice - once for this check, and once for the actual inserts, further
1126
1171
           below.  that is suboptimal, but it's pretty complicated to do it the other way without rollbacks...
1127
1172
        */
1133
1178
 
1134
1179
        if ( toupdate->netLength() < objNew.objsize() ) {
1135
1180
            // doesn't fit.  reallocate -----------------------------------------------------
 
1181
            moveCounter.increment();
1136
1182
            uassert( 10003 , "failing update: objects in a capped ns cannot grow", !(d && d->isCapped()));
1137
1183
            d->paddingTooSmall();
1138
1184
            deleteRecord(ns, toupdate, dl);
1139
 
            DiskLoc res = insert(ns, objNew.objdata(), objNew.objsize(), god);
 
1185
            DiskLoc res = insert(ns, objNew.objdata(), objNew.objsize(), false, god);
1140
1186
 
1141
1187
            if (debug.nmoved == -1) // default of -1 rather than 0
1142
1188
                debug.nmoved = 1;
1152
1198
        /* have any index keys changed? */
1153
1199
        {
1154
1200
            int keyUpdates = 0;
1155
 
            int z = d->nIndexesBeingBuilt();
 
1201
            int z = d->getTotalIndexCount();
1156
1202
            for ( int x = 0; x < z; x++ ) {
1157
1203
                IndexDetails& idx = d->idx(x);
1158
1204
                IndexInterface& ii = idx.idxInterface();
1244
1290
    }
1245
1291
#endif
1246
1292
#pragma pack(1)
1247
 
    struct IDToInsert_ {
 
1293
    struct IDToInsert {
1248
1294
        char type;
1249
 
        char _id[4];
 
1295
        char id[4];
1250
1296
        OID oid;
1251
 
        IDToInsert_() {
1252
 
            type = (char) jstOID;
1253
 
            strcpy(_id, "_id");
1254
 
            verify( sizeof(IDToInsert_) == 17 );
1255
 
        }
1256
 
    } idToInsert_;
1257
 
    struct IDToInsert : public BSONElement {
1258
 
        IDToInsert() : BSONElement( ( char * )( &idToInsert_ ) ) {}
1259
 
    } idToInsert;
 
1297
 
 
1298
        IDToInsert() {
 
1299
            type = 0;
 
1300
        }
 
1301
 
 
1302
        bool needed() const { return type > 0; }
 
1303
 
 
1304
        void init() {
 
1305
            type = static_cast<char>(jstOID);
 
1306
            strcpy( id, "_id" );
 
1307
            oid.init();
 
1308
            verify( size() == 17 );
 
1309
        }
 
1310
 
 
1311
        int size() const { return sizeof( IDToInsert ); }
 
1312
 
 
1313
        const char* rawdata() const { return reinterpret_cast<const char*>( this ); }
 
1314
    };
1260
1315
#pragma pack()
1261
1316
 
1262
1317
    void DataFileMgr::insertAndLog( const char *ns, const BSONObj &o, bool god, bool fromMigrate ) {
1263
1318
        BSONObj tmp = o;
1264
 
        insertWithObjMod( ns, tmp, god );
 
1319
        insertWithObjMod( ns, tmp, false, god );
1265
1320
        logOp( "i", ns, tmp, 0, 0, fromMigrate );
1266
1321
    }
1267
1322
 
1268
1323
    /** @param o the object to insert. can be modified to add _id and thus be an in/out param
1269
1324
     */
1270
 
    DiskLoc DataFileMgr::insertWithObjMod(const char *ns, BSONObj &o, bool god) {
 
1325
    DiskLoc DataFileMgr::insertWithObjMod(const char* ns, BSONObj& o, bool mayInterrupt, bool god) {
1271
1326
        bool addedID = false;
1272
 
        DiskLoc loc = insert( ns, o.objdata(), o.objsize(), god, true, &addedID );
 
1327
        DiskLoc loc = insert( ns, o.objdata(), o.objsize(), mayInterrupt, god, true, &addedID );
1273
1328
        if( addedID && !loc.isNull() )
1274
1329
            o = BSONObj::make( loc.rec() );
1275
1330
        return loc;
1276
1331
    }
1277
1332
 
1278
 
    bool prepareToBuildIndex(const BSONObj& io, bool god, string& sourceNS, NamespaceDetails *&sourceCollection, BSONObj& fixedIndexObject );
1279
 
 
1280
1333
    // We are now doing two btree scans for all unique indexes (one here, and one when we've
1281
1334
    // written the record to the collection.  This could be made more efficient inserting
1282
1335
    // dummy data here, keeping pointers to the btree nodes holding the dummy data and then
1321
1374
        }
1322
1375
    }
1323
1376
 
1324
 
    NOINLINE_DECL DiskLoc outOfSpace(const char *ns, NamespaceDetails *d, int lenWHdr, bool god, DiskLoc extentLoc) {
 
1377
    NOINLINE_DECL DiskLoc outOfSpace(const char* ns, NamespaceDetails* d, int lenWHdr, bool god) {
1325
1378
        DiskLoc loc;
1326
1379
        if ( ! d->isCapped() ) { // size capped doesn't grow
1327
1380
            LOG(1) << "allocating new extent for " << ns << " padding:" << d->paddingFactor() << " lenWHdr: " << lenWHdr << endl;
1328
1381
            cc().database()->allocExtent(ns, Extent::followupSize(lenWHdr, d->lastExtentSize), false, !god);
1329
 
            loc = d->alloc(ns, lenWHdr, extentLoc);
 
1382
            loc = d->alloc(ns, lenWHdr);
1330
1383
            if ( loc.isNull() ) {
1331
 
                log() << "warning: alloc() failed after allocating new extent. lenWHdr: " << lenWHdr << " last extent size:" << d->lastExtentSize << "; trying again\n";
 
1384
                log() << "warning: alloc() failed after allocating new extent. lenWHdr: " << lenWHdr << " last extent size:" << d->lastExtentSize << "; trying again" << endl;
1332
1385
                for ( int z=0; z<10 && lenWHdr > d->lastExtentSize; z++ ) {
1333
1386
                    log() << "try #" << z << endl;
1334
1387
                    cc().database()->allocExtent(ns, Extent::followupSize(lenWHdr, d->lastExtentSize), false, !god);
1335
 
                    loc = d->alloc(ns, lenWHdr, extentLoc);
 
1388
                    loc = d->alloc(ns, lenWHdr);
1336
1389
                    if ( ! loc.isNull() )
1337
1390
                        break;
1338
1391
                }
1344
1397
    /** used by insert and also compact
1345
1398
      * @return null loc if out of space 
1346
1399
      */
1347
 
    DiskLoc allocateSpaceForANewRecord(const char *ns, NamespaceDetails *d, int lenWHdr, bool god) {
1348
 
        DiskLoc extentLoc;
1349
 
        DiskLoc loc = d->alloc(ns, lenWHdr, extentLoc);
 
1400
    DiskLoc allocateSpaceForANewRecord(const char* ns, NamespaceDetails* d, int lenWHdr, bool god) {
 
1401
        DiskLoc loc = d->alloc(ns, lenWHdr);
1350
1402
        if ( loc.isNull() ) {
1351
 
            loc = outOfSpace(ns, d, lenWHdr, god, extentLoc);
 
1403
            loc = outOfSpace(ns, d, lenWHdr, god);
1352
1404
        }
1353
1405
        return loc;
1354
1406
    }
1357
1409
        uassert( 10095 , "attempt to insert in reserved database name 'system'", sys != ns);
1358
1410
        if ( strstr(ns, ".system.") ) {
1359
1411
            // later:check for dba-type permissions here if have that at some point separate
1360
 
            if ( strstr(ns, ".system.indexes" ) )
 
1412
            if (NamespaceString(ns).coll == "system.indexes")
1361
1413
                wouldAddIndex = true;
1362
1414
            else if ( legalClientSystemNS( ns , true ) ) {
1363
1415
                if ( obuf && strstr( ns , ".system.users" ) ) {
1364
1416
                    BSONObj t( reinterpret_cast<const char *>( obuf ) );
1365
 
                    uassert( 14051 , "system.users entry needs 'user' field to be a string" , t["user"].type() == String );
1366
 
                    uassert( 14052 , "system.users entry needs 'pwd' field to be a string" , t["pwd"].type() == String );
1367
 
                    uassert( 14053 , "system.users entry needs 'user' field to be non-empty" , t["user"].String().size() );
1368
 
                    uassert( 14054 , "system.users entry needs 'pwd' field to be non-empty" , t["pwd"].String().size() );
 
1417
                    uassertStatusOK(AuthorizationManager::checkValidPrivilegeDocument(
 
1418
                                            nsToDatabaseSubstring(ns), t));
1369
1419
                }
1370
1420
            }
1371
1421
            else if ( !god ) {
1372
 
                // todo this should probably uasseert rather than doing this:
1373
 
                log() << "ERROR: attempt to insert in system namespace " << ns << endl;
1374
 
                return false;
 
1422
                uasserted(16459, str::stream() << "attempt to insert in system namespace '"
 
1423
                                               << ns << "'");
1375
1424
            }
1376
1425
        }
1377
1426
        return true;
1390
1439
        NamespaceDetails *d = nsdetails(ns);
1391
1440
        if ( !god )
1392
1441
            ensureIdIndexForNewNs(ns);
 
1442
        _ensureSystemIndexes(ns);
1393
1443
        addNewNamespaceToCatalog(ns);
1394
1444
        return d;
1395
1445
    }
1396
1446
 
1397
 
    void NOINLINE_DECL insert_makeIndex(NamespaceDetails *tableToIndex, const string& tabletoidxns, const DiskLoc& loc) { 
1398
 
        uassert( 13143 , "can't create index on system.indexes" , tabletoidxns.find( ".system.indexes" ) == string::npos );
 
1447
    void NOINLINE_DECL insert_makeIndex(NamespaceDetails* tableToIndex,
 
1448
                                        const string& tabletoidxns,
 
1449
                                        const DiskLoc& loc,
 
1450
                                        bool mayInterrupt) {
 
1451
        uassert(13143,
 
1452
                "can't create index on system.indexes",
 
1453
                NamespaceString(tabletoidxns).coll != "system.indexes");
1399
1454
 
1400
1455
        BSONObj info = loc.obj();
1401
1456
        bool background = info["background"].trueValue();
1407
1462
            background = false;
1408
1463
        }
1409
1464
 
1410
 
        int idxNo = tableToIndex->nIndexes;
1411
 
        IndexDetails& idx = tableToIndex->addIndex(tabletoidxns.c_str(), !background); // clear transient info caches so they refresh; increments nIndexes
1412
 
        getDur().writingDiskLoc(idx.info) = loc;
 
1465
        // The total number of indexes right before we write to the collection
 
1466
        int oldNIndexes = -1;
 
1467
        int idxNo = tableToIndex->getTotalIndexCount();
 
1468
        std::string idxName = info["name"].valuestr();
 
1469
 
 
1470
        // Set curop description before setting indexBuildInProg, so that there's something
 
1471
        // commands can find and kill as soon as indexBuildInProg is set. Only set this if it's a
 
1472
        // killable index, so we don't overwrite commands in currentOp.
 
1473
        if (mayInterrupt) {
 
1474
            cc().curop()->setQuery(info);
 
1475
        }
 
1476
 
1413
1477
        try {
1414
 
            buildAnIndex(tabletoidxns, tableToIndex, idx, idxNo, background);
 
1478
            IndexDetails& idx = tableToIndex->getNextIndexDetails(tabletoidxns.c_str());
 
1479
            // It's important that this is outside the inner try/catch so that we never try to call
 
1480
            // kill_idx on a half-formed disk loc (if this asserts).
 
1481
            getDur().writingDiskLoc(idx.info) = loc;
 
1482
 
 
1483
            try {
 
1484
                getDur().writingInt(tableToIndex->indexBuildsInProgress) += 1;
 
1485
                buildAnIndex(tabletoidxns, tableToIndex, idx, background, mayInterrupt);
 
1486
            }
 
1487
            catch (DBException& e) {
 
1488
                // save our error msg string as an exception or dropIndexes will overwrite our message
 
1489
                LastError *le = lastError.get();
 
1490
                int savecode = 0;
 
1491
                string saveerrmsg;
 
1492
                if ( le ) {
 
1493
                    savecode = le->code;
 
1494
                    saveerrmsg = le->msg;
 
1495
                }
 
1496
                else {
 
1497
                    savecode = e.getCode();
 
1498
                    saveerrmsg = e.what();
 
1499
                }
 
1500
 
 
1501
                // Recalculate the index # so we can remove it from the list in the next catch
 
1502
                idxNo = IndexBuildsInProgress::get(tabletoidxns.c_str(), idxName);
 
1503
                // roll back this index
 
1504
                idx.kill_idx();
 
1505
 
 
1506
                verify(le && !saveerrmsg.empty());
 
1507
                setLastError(savecode,saveerrmsg.c_str());
 
1508
                throw;
 
1509
            }
 
1510
 
 
1511
            // Recompute index numbers
 
1512
            tableToIndex = nsdetails(tabletoidxns);
 
1513
            idxNo = IndexBuildsInProgress::get(tabletoidxns.c_str(), idxName);
 
1514
            verify(idxNo > -1);
 
1515
 
 
1516
            // Make sure the newly created index is relocated to nIndexes, if it isn't already there
 
1517
            if (idxNo != tableToIndex->nIndexes) {
 
1518
                log() << "switching indexes at position " << idxNo << " and "
 
1519
                      << tableToIndex->nIndexes << endl;
 
1520
                // We cannot use idx here, as it may point to a different index entry if it was
 
1521
                // flipped during building
 
1522
                IndexDetails temp = tableToIndex->idx(idxNo);
 
1523
                *getDur().writing(&tableToIndex->idx(idxNo)) =
 
1524
                    tableToIndex->idx(tableToIndex->nIndexes);
 
1525
                *getDur().writing(&tableToIndex->idx(tableToIndex->nIndexes)) = temp;
 
1526
 
 
1527
                // We also have to flip multikey entries
 
1528
                bool tempMultikey = tableToIndex->isMultikey(idxNo);
 
1529
                tableToIndex->setIndexIsMultikey(tabletoidxns.c_str(), idxNo,
 
1530
                                                 tableToIndex->isMultikey(tableToIndex->nIndexes));
 
1531
                tableToIndex->setIndexIsMultikey(tabletoidxns.c_str(), tableToIndex->nIndexes,
 
1532
                                                 tempMultikey);
 
1533
 
 
1534
                idxNo = tableToIndex->nIndexes;
 
1535
            }
 
1536
 
 
1537
            // Store the current total of indexes in case something goes wrong actually adding the
 
1538
            // index
 
1539
            oldNIndexes = tableToIndex->getTotalIndexCount();
 
1540
 
 
1541
            // clear transient info caches so they refresh; increments nIndexes
 
1542
            tableToIndex->addIndex(tabletoidxns.c_str());
 
1543
            getDur().writingInt(tableToIndex->indexBuildsInProgress) -= 1;
 
1544
 
 
1545
            IndexType* indexType = idx.getSpec().getType();
 
1546
            const IndexPlugin *plugin = indexType ? indexType->getPlugin() : NULL;
 
1547
            if (plugin) {
 
1548
                plugin->postBuildHook( idx.getSpec() );
 
1549
            }
 
1550
 
1415
1551
        }
1416
 
        catch( DBException& e ) {
1417
 
            // save our error msg string as an exception or dropIndexes will overwrite our message
1418
 
            LastError *le = lastError.get();
1419
 
            int savecode = 0;
1420
 
            string saveerrmsg;
1421
 
            if ( le ) {
1422
 
                savecode = le->code;
1423
 
                saveerrmsg = le->msg;
1424
 
            }
1425
 
            else {
1426
 
                savecode = e.getCode();
1427
 
                saveerrmsg = e.what();
1428
 
            }
1429
 
 
1430
 
            // roll back this index
1431
 
            string name = idx.indexName();
1432
 
            BSONObjBuilder b;
1433
 
            string errmsg;
1434
 
            bool ok = dropIndexes(tableToIndex, tabletoidxns.c_str(), name.c_str(), errmsg, b, true);
1435
 
            if( !ok ) {
1436
 
                log() << "failed to drop index after a unique key error building it: " << errmsg << ' ' << tabletoidxns << ' ' << name << endl;
1437
 
            }
1438
 
 
1439
 
            verify( le && !saveerrmsg.empty() );
1440
 
            setLastError(savecode,saveerrmsg.c_str());
 
1552
        catch (...) {
 
1553
            // Generally, this will be called as an exception from building the index bubbles up.
 
1554
            // Thus, the index will have already been cleaned up.  This catch just ensures that the
 
1555
            // metadata is consistent on any exception. It may leak like a sieve if the index
 
1556
            // successfully finished building and addIndex or kill_idx threw.
 
1557
 
 
1558
            // Check if nIndexes was incremented
 
1559
            if (oldNIndexes != -1 && oldNIndexes != tableToIndex->nIndexes) {
 
1560
                getDur().writingInt(tableToIndex->nIndexes) = oldNIndexes;
 
1561
            }
 
1562
 
 
1563
            // Move any other in prog indexes "back" one. It is important that idxNo is set
 
1564
            // correctly so that the correct index is removed
 
1565
            IndexBuildsInProgress::remove(tabletoidxns.c_str(), idxNo);
 
1566
            getDur().writingInt(tableToIndex->indexBuildsInProgress) -= 1;
 
1567
 
1441
1568
            throw;
1442
1569
        }
1443
1570
    }
1444
1571
 
1445
 
    /* if god==true, you may pass in obuf of NULL and then populate the returned DiskLoc
1446
 
         after the call -- that will prevent a double buffer copy in some cases (btree.cpp).
1447
 
 
1448
 
       @param mayAddIndex almost always true, except for invocation from rename namespace command.
1449
 
       @param addedID if not null, set to true if adding _id element. you must assure false before calling
1450
 
              if using.
1451
 
    */
1452
 
 
1453
 
    DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god, bool mayAddIndex, bool *addedID) {
 
1572
    // indexName is passed in because index details may not be pointing to something valid at this
 
1573
    // point
 
1574
    int IndexBuildsInProgress::get(const char* ns, const std::string& indexName) {
 
1575
        Lock::assertWriteLocked(ns);
 
1576
        NamespaceDetails* nsd = nsdetails(ns);
 
1577
 
 
1578
        // Go through unfinished index builds and try to find this index
 
1579
        for (int i=nsd->nIndexes; i<nsd->nIndexes+nsd->indexBuildsInProgress; i++) {
 
1580
            if (indexName == nsd->idx(i).indexName()) {
 
1581
                return i;
 
1582
            }
 
1583
        }
 
1584
 
 
1585
        return -1;
 
1586
    }
 
1587
 
 
1588
    void IndexBuildsInProgress::remove(const char* ns, int offset) {
 
1589
        Lock::assertWriteLocked(ns);
 
1590
        NamespaceDetails* nsd = nsdetails(ns);
 
1591
 
 
1592
        for (int i=offset; i<nsd->getTotalIndexCount(); i++) {
 
1593
            if (i < NamespaceDetails::NIndexesMax-1) {
 
1594
                *getDur().writing(&nsd->idx(i)) = nsd->idx(i+1);
 
1595
                nsd->setIndexIsMultikey(ns, i, nsd->isMultikey(i+1));
 
1596
            }
 
1597
            else {
 
1598
                *getDur().writing(&nsd->idx(i)) = IndexDetails();
 
1599
                nsd->setIndexIsMultikey(ns, i, false);
 
1600
            }
 
1601
        }
 
1602
    }
 
1603
 
 
1604
    DiskLoc DataFileMgr::insert(const char* ns,
 
1605
                                const void* obuf,
 
1606
                                int32_t len,
 
1607
                                bool mayInterrupt,
 
1608
                                bool god,
 
1609
                                bool mayAddIndex,
 
1610
                                bool* addedID) {
1454
1611
        bool wouldAddIndex = false;
1455
1612
        massert( 10093 , "cannot insert into reserved $ collection", god || NamespaceString::normal( ns ) );
1456
1613
        uassert( 10094 , str::stream() << "invalid ns: " << ns , isValidNS( ns ) );
1473
1630
        if ( addIndex ) {
1474
1631
            verify( obuf );
1475
1632
            BSONObj io((const char *) obuf);
1476
 
            if( !prepareToBuildIndex(io, god, tabletoidxns, tableToIndex, fixedIndexObject ) ) {
 
1633
            if( !prepareToBuildIndex(io,
 
1634
                                     mayInterrupt,
 
1635
                                     god,
 
1636
                                     tabletoidxns,
 
1637
                                     tableToIndex,
 
1638
                                     fixedIndexObject) ) {
1477
1639
                // prepare creates _id itself, or this indicates to fail the build silently (such 
1478
1640
                // as if index already exists)
1479
1641
                return DiskLoc();
1484
1646
            }
1485
1647
        }
1486
1648
 
1487
 
        int addID = 0; // 0 if not adding _id; if adding, the length of that new element
 
1649
        IDToInsert idToInsert; // only initialized if needed
 
1650
 
1488
1651
        if( !god ) {
1489
1652
            /* Check if we have an _id field. If we don't, we'll add it.
1490
1653
               Note that btree buckets which we insert aren't BSONObj's, but in that case god==true.
1493
1656
            BSONElement idField = io.getField( "_id" );
1494
1657
            uassert( 10099 ,  "_id cannot be an array", idField.type() != Array );
1495
1658
            // we don't add _id for capped collections in local as they don't have an _id index
1496
 
            if( idField.eoo() && !wouldAddIndex &&
1497
 
                !str::equals( nsToDatabase( ns ).c_str() , "local" ) && d->haveIdIndex() ) {
 
1659
            if( idField.eoo() &&
 
1660
                !wouldAddIndex &&
 
1661
                nsToDatabase( ns ) != "local" &&
 
1662
                d->haveIdIndex() ) {
 
1663
 
1498
1664
                if( addedID )
1499
1665
                    *addedID = true;
1500
 
                addID = len;
1501
 
                idToInsert_.oid.init();
 
1666
 
 
1667
                idToInsert.init();
1502
1668
                len += idToInsert.size();
1503
1669
            }
1504
1670
 
1518
1684
 
1519
1685
        bool earlyIndex = true;
1520
1686
        DiskLoc loc;
1521
 
        if( addID || tableToIndex || d->isCapped() ) {
 
1687
        if( idToInsert.needed() || tableToIndex || d->isCapped() ) {
1522
1688
            // if need id, we don't do the early indexing. this is not the common case so that is sort of ok
1523
1689
            earlyIndex = false;
1524
1690
            loc = allocateSpaceForANewRecord(ns, d, lenWHdr, god);
1561
1727
        {
1562
1728
            verify( r->lengthWithHeaders() >= lenWHdr );
1563
1729
            r = (Record*) getDur().writingPtr(r, lenWHdr);
1564
 
            if( addID ) {
 
1730
            if( idToInsert.needed() ) {
1565
1731
                /* a little effort was made here to avoid a double copy when we add an ID */
1566
 
                ((int&)*r->data()) = *((int*) obuf) + idToInsert.size();
 
1732
                int originalSize = *((int*) obuf);
 
1733
                ((int&)*r->data()) = originalSize + idToInsert.size();
1567
1734
                memcpy(r->data()+4, idToInsert.rawdata(), idToInsert.size());
1568
 
                memcpy(r->data()+4+idToInsert.size(), ((char *)obuf)+4, addID-4);
 
1735
                memcpy(r->data()+4+idToInsert.size(), ((char*)obuf)+4, originalSize-4);
1569
1736
            }
1570
1737
            else {
1571
1738
                if( obuf ) // obuf can be null from internal callers
1587
1754
            NamespaceDetailsTransient::get( ns ).notifyOfWriteOp();
1588
1755
 
1589
1756
        if ( tableToIndex ) {
1590
 
            insert_makeIndex(tableToIndex, tabletoidxns, loc);
 
1757
            insert_makeIndex(tableToIndex, tabletoidxns, loc, mayInterrupt);
1591
1758
        }
1592
1759
 
1593
1760
        /* add this record to our indexes */
1630
1797
        RARELY verify( d == nsdetails(ns) );
1631
1798
        DEV verify( d == nsdetails(ns) );
1632
1799
 
1633
 
        DiskLoc extentLoc;
 
1800
        massert( 16509,
 
1801
                 str::stream()
 
1802
                 << "fast_oplog_insert requires a capped collection "
 
1803
                 << " but " << ns << " is not capped",
 
1804
                 d->isCapped() );
 
1805
 
 
1806
        //record timing on oplog inserts
 
1807
        boost::optional<TimerHolder> insertTimer;
 
1808
        //skip non-oplog collections
 
1809
        if (NamespaceString::oplog(ns)) {
 
1810
            insertTimer = boost::in_place(&oplogInsertStats);
 
1811
            oplogInsertBytesStats.increment(len); //record len of inserted records for oplog
 
1812
        }
 
1813
 
1634
1814
        int lenWHdr = len + Record::HeaderSize;
1635
 
        DiskLoc loc = d->alloc(ns, lenWHdr, extentLoc);
 
1815
        DiskLoc loc = d->alloc(ns, lenWHdr);
1636
1816
        verify( !loc.isNull() );
1637
1817
 
1638
1818
        Record *r = loc.rec();
1686
1866
        }
1687
1867
    }
1688
1868
 
1689
 
    void dropDatabase(string db) {
 
1869
    void dropDatabase(const std::string& db) {
1690
1870
        LOG(1) << "dropDatabase " << db << endl;
1691
1871
        Lock::assertWriteLocked(db);
1692
1872
        Database *d = cc().database();
1736
1916
            virtual bool apply( const Path &p ) {
1737
1917
                if ( !boost::filesystem::exists( p ) )
1738
1918
                    return false;
1739
 
                boostRenameWrapper( p, newPath_ / ( p.leaf() + ".bak" ) );
 
1919
                boostRenameWrapper( p, newPath_ / ( p.leaf().string() + ".bak" ) );
1740
1920
                return true;
1741
1921
            }
1742
1922
            virtual const char * op() const {
1844
2024
            uniqueReservedPath( ( preserveClonedFilesOnFailure || backupOriginalFiles ) ?
1845
2025
                                "backup" : "_tmp" );
1846
2026
        MONGO_ASSERT_ON_EXCEPTION( boost::filesystem::create_directory( reservedPath ) );
1847
 
        string reservedPathString = reservedPath.native_directory_string();
 
2027
        string reservedPathString = reservedPath.string();
1848
2028
 
1849
2029
        bool res;
1850
2030
        {
1852
2032
            Client::Context ctx( dbName, reservedPathString );
1853
2033
            verify( ctx.justCreated() );
1854
2034
 
1855
 
            res = cloneFrom(localhost.c_str(), errmsg, dbName,
1856
 
                            /*logForReplication=*/false, /*slaveOk*/false, /*replauth*/false,
1857
 
                            /*snapshot*/false, /*mayYield*/false, /*mayBeInterrupted*/true);
 
2035
            res = Cloner::cloneFrom(localhost.c_str(), errmsg, dbName,
 
2036
                                    /*logForReplication=*/false, /*slaveOk*/false,
 
2037
                                    /*replauth*/false, /*snapshot*/false, /*mayYield*/false,
 
2038
                                    /*mayBeInterrupted*/true);
 
2039
 
1858
2040
            Database::closeDatabase( dbName, reservedPathString.c_str() );
1859
2041
        }
1860
2042