summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2013-12-20 18:55:43 -0500
committerEliot Horowitz <eliot@10gen.com>2013-12-22 20:21:50 -0500
commit90bdeb9e6657afb9ca71a62db0996c040e0fafdd (patch)
tree2fe1846242d0fb71997cf307cdfe41fffc103387 /src/mongo
parent68f0e4c16e9c38b8a04c697e58c6ff81f04a9c6e (diff)
downloadmongo-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.cpp9
-rw-r--r--src/mongo/db/catalog/ondisk/namespace_index.cpp6
-rw-r--r--src/mongo/db/commands/dbhash.cpp4
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp4
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp4
-rw-r--r--src/mongo/db/database.cpp5
-rw-r--r--src/mongo/db/instance.cpp12
-rw-r--r--src/mongo/db/namespace_details.cpp8
-rw-r--r--src/mongo/db/namespace_details.h16
-rw-r--r--src/mongo/db/ops/insert.cpp57
-rw-r--r--src/mongo/db/ops/insert.h10
-rw-r--r--src/mongo/db/repl/oplog.cpp6
-rw-r--r--src/mongo/db/structure/collection.cpp31
-rw-r--r--src/mongo/db/structure/collection.h6
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;