diff --git a/db/jsobj.h b/db/jsobj.h index bcd729b6518..c133b8db203 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -337,7 +337,7 @@ namespace mongo { */ int woCompare( const BSONElement &e, bool considerFieldName = true ) const; - const char * rawdata() { + const char * rawdata() const { return data; } @@ -356,7 +356,7 @@ namespace mongo { type() == CodeWScope; } - private: + protected: // If maxLen is specified, don't scan more than maxLen bytes. BSONElement(const char *d, int maxLen = -1) : data(d) { if ( eoo() ) @@ -372,6 +372,7 @@ namespace mongo { } totalSize = -1; } + private: const char *data; int fieldNameSize; mutable int totalSize; /* caches the computed size */ diff --git a/db/pdfile.cpp b/db/pdfile.cpp index 3515174f50d..226e37375f3 100644 --- a/db/pdfile.cpp +++ b/db/pdfile.cpp @@ -677,14 +677,15 @@ namespace mongo { NamespaceDetails *d = nsdetails(ns); + BSONObj objOld(toupdate); + BSONElement idOld; + int addID = 0; { /* duplicate _id check... */ BSONObj objNew(buf); - BSONObj objOld(toupdate); BSONElement idNew; + objOld.getObjectID(idOld); if( objNew.getObjectID(idNew) ) { - BSONElement idOld; - objOld.getObjectID(idOld); if( idOld == idNew ) ; else { @@ -699,8 +700,12 @@ namespace mongo { !Helpers::findOne(ns, b.done(), result)); } } + } else { + if ( !idOld.eoo() ) { + addID = len; + len += idOld.size(); + } } - } if ( toupdate->netLength() < len ) { @@ -715,7 +720,7 @@ namespace mongo { if ( database->profile ) ss << " moved "; deleteRecord(ns, toupdate, dl); - insert(ns, buf, len); + insert(ns, buf, len, false, idOld); return; } @@ -770,7 +775,13 @@ namespace mongo { } // update in place - memcpy(toupdate->data, buf, len); + if ( addID ) { + ((int&)*toupdate->data) = *((int*) buf) + idOld.size(); + memcpy(toupdate->data+4, idOld.rawdata(), idOld.size()); + memcpy(toupdate->data+4+idOld.size(), ((char *)buf)+4, addID-4); + } else { + memcpy(toupdate->data, buf, len); + } } int followupExtentSize(int len, int lastExtentLen) { @@ -892,19 +903,22 @@ namespace mongo { } #pragma pack(1) - struct IDToInsert { + struct IDToInsert_ { char type; char _id[4]; OID oid; - IDToInsert() { + IDToInsert_() { type = (char) jstOID; strcpy(_id, "_id"); - assert( sizeof(IDToInsert) == 17 ); + assert( sizeof(IDToInsert_) == 17 ); } + } idToInsert_; + struct IDToInsert : public BSONElement { + IDToInsert() : BSONElement( ( char * )( &idToInsert_ ) ) {} } idToInsert; #pragma pack() - - DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god) { + + DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god, const BSONElement &writeId) { bool addIndex = false; const char *sys = strstr(ns, "system."); if ( sys ) { @@ -988,6 +1002,7 @@ namespace mongo { //indexFullNS += name; // database.table.$index -- note this doesn't contain jsobjs, it contains BtreeBuckets. } + const BSONElement *newId = &writeId; int addID = 0; if( !god ) { /* Check if we have an _id field. If we don't, we'll add it. @@ -996,7 +1011,12 @@ namespace mongo { BSONObj io((const char *) obuf); if( !io.hasField("_id") && !addIndex && strstr(ns, ".local.") == 0 ) { addID = len; - len += sizeof(IDToInsert); + if ( writeId.eoo() ) { + // Very likely we'll add this elt, so little harm in init'ing here. + idToInsert_.oid.init(); + newId = &idToInsert; + } + len += newId->size(); } } @@ -1028,10 +1048,9 @@ namespace mongo { assert( r->lengthWithHeaders >= lenWHdr ); if( addID ) { /* a little effort was made here to avoid a double copy when we add an ID */ - idToInsert.oid.init(); - ((int&)*r->data) = *((int*) obuf) + sizeof(idToInsert); - memcpy(r->data+4, &idToInsert, sizeof(idToInsert)); - memcpy(r->data+4+sizeof(idToInsert), ((char *)obuf)+4, addID-4); + ((int&)*r->data) = *((int*) obuf) + newId->size(); + memcpy(r->data+4, newId->rawdata(), newId->size()); + memcpy(r->data+4+newId->size(), ((char *)obuf)+4, addID-4); // TEMP: BSONObj foo(r->data); cout << "TEMP:" << foo.toString() << endl; diff --git a/db/pdfile.h b/db/pdfile.h index 5358b91bfbd..7dc870adcfb 100644 --- a/db/pdfile.h +++ b/db/pdfile.h @@ -87,7 +87,7 @@ namespace mongo { const char *ns, Record *toupdate, const DiskLoc& dl, const char *buf, int len, stringstream& profiling); - DiskLoc insert(const char *ns, const void *buf, int len, bool god = false); + DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement()); void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false); static auto_ptr findAll(const char *ns); diff --git a/jstests/autoid.js b/jstests/autoid.js new file mode 100644 index 00000000000..4f12645201a --- /dev/null +++ b/jstests/autoid.js @@ -0,0 +1,18 @@ +p = function( o ) { + print( tojson( o ) ); +} + +f = db.jstests_autoid; +f.drop(); + +f.save( {z:1} ); +a = f.findOne( {z:1} ); +p( a ); +f.update( {z:1}, {z:2} ); +b = f.findOne( {z:2} ); +p( b ); +//assert.eq( a._id, b._id ); +c = f.update( {z:2}, {z:"abcdefgabcdefgabcdefg"} ); +c = f.findOne( {} ); +p( c ); +//assert.eq( a._id, c._id ); diff --git a/mongo.xcodeproj/project.pbxproj b/mongo.xcodeproj/project.pbxproj index 587375bfd78..509955c9ecf 100644 --- a/mongo.xcodeproj/project.pbxproj +++ b/mongo.xcodeproj/project.pbxproj @@ -175,6 +175,7 @@ 93A8D20F0F37544800C92B85 /* update.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update.js; sourceTree = ""; }; 93A8D2100F37544800C92B85 /* update2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = update2.js; sourceTree = ""; }; 93A8D2110F37544800C92B85 /* where1.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = where1.js; sourceTree = ""; }; + 93A8D8200F38FE2400C92B85 /* autoid.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = autoid.js; sourceTree = ""; }; 93AF75500F216D0300994C66 /* jsontests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jsontests.cpp; sourceTree = ""; }; 93B4A81A0F1C01B4000C862C /* security.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = security.cpp; sourceTree = ""; }; 93B4A81B0F1C01D8000C862C /* lasterror.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lasterror.cpp; sourceTree = ""; }; @@ -391,6 +392,7 @@ 93A8D1D10F37544800C92B85 /* jstests */ = { isa = PBXGroup; children = ( + 93A8D8200F38FE2400C92B85 /* autoid.js */, 93A8D1D30F37544800C92B85 /* _runner.js */, 93A8D1D40F37544800C92B85 /* apitest_db.js */, 93A8D1D50F37544800C92B85 /* apitest_dbcollection.js */,