diff options
author | Eliot Horowitz <eliot@10gen.com> | 2013-12-20 18:55:43 -0500 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2013-12-22 20:21:50 -0500 |
commit | 90bdeb9e6657afb9ca71a62db0996c040e0fafdd (patch) | |
tree | 2fe1846242d0fb71997cf307cdfe41fffc103387 /src/mongo | |
parent | 68f0e4c16e9c38b8a04c697e58c6ff81f04a9c6e (diff) | |
download | mongo-90bdeb9e6657afb9ca71a62db0996c040e0fafdd.tar.gz |
SERVER-11611: move all user facing inserts to Collection::insertDocument
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/index_catalog.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/catalog/ondisk/namespace_index.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/commands/dbhash.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/batch_executor.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/database.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/instance.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/namespace_details.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/namespace_details.h | 16 | ||||
-rw-r--r-- | src/mongo/db/ops/insert.cpp | 57 | ||||
-rw-r--r-- | src/mongo/db/ops/insert.h | 10 | ||||
-rw-r--r-- | src/mongo/db/repl/oplog.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/structure/collection.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/structure/collection.h | 6 |
14 files changed, 149 insertions, 29 deletions
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index c3e0f08b70d..26c4bb09da6 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -376,6 +376,15 @@ namespace mongo { return Status( ErrorCodes::IndexAlreadyExists, "cannot index freelist" ); } + StringData specNamespace = spec.getStringField("ns"); + if ( specNamespace.size() == 0 ) + return Status( ErrorCodes::CannotCreateIndex, + "the index spec needs a 'ns' field'" ); + + if ( _collection->ns() != specNamespace ) + return Status( ErrorCodes::CannotCreateIndex, + "the index spec ns does not match" ); + // logical name of the index const char *name = spec.getStringField("name"); if ( !name[0] ) diff --git a/src/mongo/db/catalog/ondisk/namespace_index.cpp b/src/mongo/db/catalog/ondisk/namespace_index.cpp index 7e2b3d1b1c4..cbb6a7a871c 100644 --- a/src/mongo/db/catalog/ondisk/namespace_index.cpp +++ b/src/mongo/db/catalog/ondisk/namespace_index.cpp @@ -62,9 +62,11 @@ namespace mongo { } void NamespaceIndex::add_ns( const Namespace& ns, const NamespaceDetails* details ) { - Lock::assertWriteLocked(ns.toString()); + string nsString = ns.toString(); + Lock::assertWriteLocked( nsString ); + massert( 17315, "no . in ns", nsString.find( '.' ) != string::npos ); init(); - uassert( 10081 , "too many namespaces/collections", _ht->put(ns, *details)); + uassert( 10081, "too many namespaces/collections", _ht->put(ns, *details)); } void NamespaceIndex::kill_ns(const StringData& ns) { diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index ab986fc2780..78e0e33cf35 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -161,6 +161,10 @@ namespace mongo { BSONObjBuilder bb( result.subobjStart( "collections" ) ); for ( list<string>::iterator i=colls.begin(); i != colls.end(); i++ ) { string fullCollectionName = *i; + if ( fullCollectionName.size() -1 <= dbname.size() ) { + errmsg = str::stream() << "weird fullCollectionName [" << fullCollectionName << "]"; + return false; + } string shortCollectionName = fullCollectionName.substr( dbname.size() + 1 ); if ( shortCollectionName.find( "system." ) == 0 ) diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index c5e4811d8db..ec28b363478 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -468,7 +468,9 @@ namespace mongo { return false; } } - Status status = collection->getIndexCatalog()->createIndex( insertOp, true ); + + bool mayInterrupt = cc().curop()->parent() == NULL; + Status status = collection->getIndexCatalog()->createIndex( insertOp, mayInterrupt ); if ( status.code() == ErrorCodes::IndexAlreadyExists ) return true; if ( !status.isOK() ) { diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index a00eb4f3879..dcc9341426d 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -127,6 +127,10 @@ namespace mongo { NamespaceString nss(dbName, request.getNS()); request.setNS(nss.ns()); + Status status = userAllowedWriteNS( nss ); + if ( !status.isOK() ) + return appendCommandStatus( result, status ); + if ( cc().curop() ) cc().curop()->setNS( nss.ns() ); diff --git a/src/mongo/db/database.cpp b/src/mongo/db/database.cpp index 999c24f4afe..8b146d5cf7d 100644 --- a/src/mongo/db/database.cpp +++ b/src/mongo/db/database.cpp @@ -568,7 +568,10 @@ namespace mongo { // TODO: option for: allocation, indexes? - if ( nsToCollectionSubstring( ns ).startsWith( "system." ) ) { + StringData collectionName = nsToCollectionSubstring( ns ); + uassert( 17314, "cannot create a blank collection", collectionName.size() ); + + if ( collectionName.startsWith( "system." ) ) { authindex::createSystemIndexes( ns ); } diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 5c98f815efa..25778602d02 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -588,6 +588,7 @@ namespace mongo { void receivedUpdate(Message& m, CurOp& op) { DbMessage d(m); NamespaceString ns(d.getns()); + uassertStatusOK( userAllowedWriteNS( ns ) ); op.debug().ns = ns.ns(); int flags = d.pullInt(); BSONObj query = d.nextJsObj(); @@ -673,6 +674,7 @@ namespace mongo { void receivedDelete(Message& m, CurOp& op) { DbMessage d(m); NamespaceString ns(d.getns()); + uassertStatusOK( userAllowedWriteNS( ns ) ); op.debug().ns = ns.ns(); int flags = d.pullInt(); @@ -843,6 +845,7 @@ namespace mongo { void checkAndInsert(Client::Context& ctx, const char *ns, /*modifies*/BSONObj& js) { if ( nsToCollectionSubstring( ns ) == "system.indexes" ) { string targetNS = js["ns"].String(); + uassertStatusOK( userAllowedWriteNS( targetNS ) ); Collection* collection = ctx.db()->getCollection( targetNS ); if ( !collection ) { @@ -851,9 +854,12 @@ namespace mongo { verify( collection ); } - Status status = collection->getIndexCatalog()->createIndex( js, true ); + bool mayInterrupt = cc().curop()->parent() == NULL; + Status status = collection->getIndexCatalog()->createIndex( js, mayInterrupt ); + if ( status.code() == ErrorCodes::IndexAlreadyExists ) return; + uassertStatusOK( status ); logOp( "i", ns, js ); return; @@ -861,6 +867,8 @@ namespace mongo { StatusWith<BSONObj> fixed = fixDocumentForInsert( js ); uassertStatusOK( fixed.getStatus() ); + if ( !fixed.getValue().isEmpty() ) + js = fixed.getValue(); Collection* collection = ctx.db()->getCollection( ns ); if ( !collection ) { @@ -897,6 +905,8 @@ namespace mongo { const char *ns = d.getns(); op.debug().ns = ns; + uassertStatusOK( userAllowedWriteNS( ns ) ); + if( !d.moreJSObjs() ) { // strange. should we complain? return; diff --git a/src/mongo/db/namespace_details.cpp b/src/mongo/db/namespace_details.cpp index 71df631a8f4..c78781b7446 100644 --- a/src/mongo/db/namespace_details.cpp +++ b/src/mongo/db/namespace_details.cpp @@ -676,7 +676,15 @@ namespace mongo { return true; } + void NamespaceDetails::setPaddingFactor( double paddingFactor ) { + if ( paddingFactor == _paddingFactor ) + return; + if ( isCapped() ) + return; + + *getDur().writing(&_paddingFactor) = paddingFactor; + } int NamespaceDetails::getRecordAllocationSize( int minRecordSize ) { diff --git a/src/mongo/db/namespace_details.h b/src/mongo/db/namespace_details.h index bfaea894017..5057fda91b1 100644 --- a/src/mongo/db/namespace_details.h +++ b/src/mongo/db/namespace_details.h @@ -306,9 +306,7 @@ namespace mongo { double paddingFactor() const { return _paddingFactor; } - void setPaddingFactor( double paddingFactor ) { - *getDur().writing(&_paddingFactor) = paddingFactor; - } + void setPaddingFactor( double paddingFactor ); /* called to indicate that an update fit in place. fits also called on an insert -- idea there is that if you had some mix and then went to @@ -321,10 +319,8 @@ namespace mongo { */ void paddingFits() { MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis to journal less - double x = _paddingFactor - 0.001; - if ( x >= 1.0 ) { - setPaddingFactor( x ); - } + double x = max(1.0, _paddingFactor - 0.001 ); + setPaddingFactor( x ); } } void paddingTooSmall() { @@ -337,10 +333,8 @@ namespace mongo { this should be an adequate starting point. */ double N = min(_nIndexes,7) + 3; - double x = _paddingFactor + (0.001 * N); - if ( x <= 2.0 ) { - setPaddingFactor( x ); - } + double x = min(2.0,_paddingFactor + (0.001 * N)); + setPaddingFactor( x ); } } diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp index 63dc1acb44b..a7c43e46c4b 100644 --- a/src/mongo/db/ops/insert.cpp +++ b/src/mongo/db/ops/insert.cpp @@ -122,4 +122,61 @@ namespace mongo { return StatusWith<BSONObj>( b.obj() ); } + Status userAllowedWriteNS( const StringData& ns ) { + return userAllowedWriteNS( nsToDatabaseSubstring( ns ), nsToCollectionSubstring( ns ) ); + } + + Status userAllowedWriteNS( const NamespaceString& ns ) { + return userAllowedWriteNS( ns.db(), ns.coll() ); + } + + Status userAllowedWriteNS( const StringData& db, const StringData& coll ) { + // validity checking + + if ( db.size() == 0 ) + return Status( ErrorCodes::BadValue, "collection cannot be blank" ); + + if ( !NamespaceString::validDBName( db ) ) + return Status( ErrorCodes::BadValue, "invalid db name" ); + + if ( coll.size() == 0 ) + return Status( ErrorCodes::BadValue, "collection cannot be blank" ); + + if ( !NamespaceString::validCollectionName( coll ) ) + return Status( ErrorCodes::BadValue, "invalid collection name" ); + + // check spceial areas + + if ( db == "system" ) + return Status( ErrorCodes::BadValue, "cannot use 'system' database" ); + + + if ( coll.startsWith( "system." ) ) { + if ( coll == "system.indexes" ) return Status::OK(); + if ( coll == "system.js" ) return Status::OK(); + if ( coll == "system.users" ) return Status::OK(); + if ( db == "admin" ) { + if ( coll == "system.version" ) return Status::OK(); + if ( coll == "system.roles" ) return Status::OK(); + if ( coll == "system.new_users" ) return Status::OK(); + if ( coll == "system.backup_users" ) return Status::OK(); + } + if ( db == "local" ) { + if ( coll == "system.replset" ) return Status::OK(); + } + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << "." << coll << "'" ); + } + + // some special rules + + if ( coll.find( ".system." ) != string::npos ) { + // this matches old (2.4 and older) behavior, but I'm not sure its a good idea + return Status( ErrorCodes::BadValue, + str::stream() << "cannot write to '" << db << "." << coll << "'" ); + } + + return Status::OK(); + } + } diff --git a/src/mongo/db/ops/insert.h b/src/mongo/db/ops/insert.h index 831a259ff1d..06ae6e3e643 100644 --- a/src/mongo/db/ops/insert.h +++ b/src/mongo/db/ops/insert.h @@ -28,6 +28,7 @@ * it in the license file. */ +#include "mongo/db/namespace_string.h" #include "mongo/db/jsobj.h" namespace mongo { @@ -39,4 +40,13 @@ namespace mongo { StatusWith<BSONObj> fixDocumentForInsert( const BSONObj& doc ); + /** + * check if this is a collection _any_ user can write to + * does NOT to permission checking, that is elsewhere + * for example, can't write to foo.system.bar + */ + Status userAllowedWriteNS( const StringData& db, const StringData& coll ); + Status userAllowedWriteNS( const StringData& ns ); + Status userAllowedWriteNS( const NamespaceString& ns ); + } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index b6ed66e9a65..a29c8c9c691 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -51,6 +51,7 @@ #include "mongo/db/repl/replication_server_status.h" #include "mongo/db/repl/rs.h" #include "mongo/db/repl/write_concern.h" +#include "mongo/scripting/engine.h" #include "mongo/db/stats/counters.h" #include "mongo/db/storage_options.h" #include "mongo/db/structure/collection.h" @@ -369,6 +370,11 @@ namespace mongo { logOpForSharding(opstr, ns, obj, patt, fullObj, fromMigrate); logOpForDbHash(opstr, ns, obj, patt, fullObj, fromMigrate); getGlobalAuthorizationManager()->logOp(opstr, ns, obj, patt, b); + + if ( strstr( ns, ".system.js" ) ) { + Scope::storedFuncMod(); // this is terrible + } + } void createOplog() { diff --git a/src/mongo/db/structure/collection.cpp b/src/mongo/db/structure/collection.cpp index 7d1e4f503b9..11c1505f52e 100644 --- a/src/mongo/db/structure/collection.cpp +++ b/src/mongo/db/structure/collection.cpp @@ -108,7 +108,6 @@ namespace mongo { } StatusWith<DiskLoc> Collection::insertDocument( const BSONObj& docToInsert, bool enforceQuota ) { - if ( _indexCatalog.findIdIndex() ) { if ( docToInsert["_id"].eoo() ) { return StatusWith<DiskLoc>( ErrorCodes::InternalError, @@ -116,9 +115,6 @@ namespace mongo { } } - int lenWHdr = _details->getRecordAllocationSize( docToInsert.objsize() + Record::HeaderSize ); - fassert( 17208, lenWHdr >= ( docToInsert.objsize() + Record::HeaderSize ) ); - if ( _details->isCapped() ) { // TOOD: old god not done Status ret = _indexCatalog.checkNoIndexConflicts( docToInsert ); @@ -126,6 +122,19 @@ namespace mongo { return StatusWith<DiskLoc>( ret ); } + StatusWith<DiskLoc> status = _insertDocument( docToInsert, enforceQuota ); + if ( status.isOK() ) { + _details->paddingFits(); + } + + return status; + } + + StatusWith<DiskLoc> Collection::_insertDocument( const BSONObj& docToInsert, bool enforceQuota ) { + + int lenWHdr = _details->getRecordAllocationSize( docToInsert.objsize() + Record::HeaderSize ); + fassert( 17208, lenWHdr >= ( docToInsert.objsize() + Record::HeaderSize ) ); + // TODO: for now, capped logic lives inside NamespaceDetails, which is hidden // under the RecordStore, this feels broken since that should be a // collection access method probably @@ -145,13 +154,12 @@ namespace mongo { _details->incrementStats( r->netLength(), 1 ); - // TOOD: old god not done _infoCache.notifyOfWriteOp(); try { _indexCatalog.indexRecord( docToInsert, loc.getValue() ); } - catch( AssertionException& e ) { + catch ( AssertionException& e ) { if ( _details->isCapped() ) { return StatusWith<DiskLoc>( ErrorCodes::InternalError, str::stream() << "unexpected index insertion failure on" @@ -159,16 +167,13 @@ namespace mongo { << " - collection and its index will not match" ); } - // normal case -- we can roll back - deleteDocument( loc.getValue(), false, true, NULL ); + // indexRecord takes care of rolling back indexes + // so we just have to delete the main storage + _recordStore.deallocRecord( loc.getValue(), r ); return StatusWith<DiskLoc>( e.toStatus( "insertDocument" ) ); } - // TODO: this is what the old code did, but is it correct? - _details->paddingFits(); - return loc; - } void Collection::deleteDocument( const DiskLoc& loc, bool cappedOK, bool noWarn, @@ -273,7 +278,7 @@ namespace mongo { debug->nmoved += 1; } - StatusWith<DiskLoc> loc = insertDocument( objNew, enforceQuota ); + StatusWith<DiskLoc> loc = _insertDocument( objNew, enforceQuota ); if ( loc.isOK() ) { // insert successful, now lets deallocate the old location diff --git a/src/mongo/db/structure/collection.h b/src/mongo/db/structure/collection.h index 564a443ce0c..de6f17d58fc 100644 --- a/src/mongo/db/structure/collection.h +++ b/src/mongo/db/structure/collection.h @@ -138,6 +138,12 @@ namespace mongo { } private: + /** + * same semantics as insertDocument, but doesn't do: + * - some user error checks + * - adjust padding + */ + StatusWith<DiskLoc> _insertDocument( const BSONObj& doc, bool enforceQuota ); // @return 0 for inf., otherwise a number of files int largestFileNumberInQuota() const; |