diff --git a/db/database.cpp b/db/database.cpp index cd4e8f4cc70..a75191308ec 100644 --- a/db/database.cpp +++ b/db/database.cpp @@ -192,22 +192,31 @@ namespace mongo { return ret; } + bool fileIndexExceedsQuota( const char *ns, int fileIndex, bool enforceQuota ) { + return + cmdLine.quota && + enforceQuota && + fileIndex >= cmdLine.quotaFiles && + // we don't enforce the quota on "special" namespaces as that could lead to problems -- e.g. + // rejecting an index insert after inserting the main record. + !NamespaceString::special( ns ) && + NamespaceString( ns ).db != "local"; + } + MongoDataFile* Database::suitableFile( const char *ns, int sizeNeeded, bool preallocate, bool enforceQuota ) { // check existing files for ( int i=numFiles()-1; i>=0; i-- ) { MongoDataFile* f = getFile( i ); if ( f->getHeader()->unusedLength >= sizeNeeded ) { - // we don't enforce the quota on "special" namespaces as that could lead to problems -- e.g. - // rejecting an index insert after inserting the main record. - if( cmdLine.quota && enforceQuota && i > cmdLine.quotaFiles && !NamespaceString::special(ns) ) + if ( fileIndexExceedsQuota( ns, i-1, enforceQuota ) ) // NOTE i-1 is the value used historically for this check. ; else return f; } } - if( cmdLine.quota && enforceQuota && numFiles() >= cmdLine.quotaFiles && !NamespaceString::special(ns) ) + if ( fileIndexExceedsQuota( ns, numFiles(), enforceQuota ) ) uasserted(12501, "quota exceeded"); // allocate files until we either get one big enough or hit maxSize diff --git a/jstests/disk/quota.js b/jstests/disk/quota.js new file mode 100644 index 00000000000..d93e5eaafc0 --- /dev/null +++ b/jstests/disk/quota.js @@ -0,0 +1,47 @@ +// Check functioning of --quotaFiles parameter, including with respect to SERVER-3293 ('local' database). + +port = allocatePorts( 1 )[ 0 ]; + +baseName = "jstests_disk_quota"; +dbpath = "/data/db/" + baseName; + +m = startMongod( "--port", port, "--dbpath", "/data/db/" + baseName, "--quotaFiles", "1", "--smallfiles" ); +db = m.getDB( baseName ); + +big = new Array( 10000 ).toString(); + +// Insert documents until quota is exhausted. +while( !db.getLastError() ) { + db[ baseName ].save( {b:big} ); +} +printjson( db.getLastError() ); + +dotTwoDataFile = dbpath + "/" + baseName + ".2"; +files = listFiles( dbpath ); +for( i in files ) { + // Since only one data file is allowed, a .0 file is expected and a .1 file may be preallocated (SERVER-3410) but no .2 file is expected. + assert.neq( dotTwoDataFile, files[ i ].name ); +} + +dotTwoDataFile = dbpath + "/" + "local" + ".2"; +// Check that quota does not apply to local db, and a .2 file can be created. +l = m.getDB( "local" )[ baseName ]; +for( i = 0; i < 10000; ++i ) { + l.save( {b:big} ); + assert( !db.getLastError() ); + dotTwoFound = false; + if ( i % 100 != 0 ) { + continue; + } + files = listFiles( dbpath ); + for( f in files ) { + if ( files[ f ].name == dotTwoDataFile ) { + dotTwoFound = true; + } + } + if ( dotTwoFound ) { + break; + } +} + +assert( dotTwoFound );