/** * Copyright (C) 2008 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #include "mongo/platform/basic.h" #include "mongo/db/storage/mmap_v1/catalog/namespace_details.h" #include #include #include "mongo/base/counter.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/collection_options.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands/server_status.h" #include "mongo/db/concurrency/locker.h" #include "mongo/db/db.h" #include "mongo/db/index_legacy.h" #include "mongo/db/json.h" #include "mongo/db/ops/delete.h" #include "mongo/db/ops/update.h" #include "mongo/db/storage/mmap_v1/catalog/namespace_index.h" #include "mongo/db/operation_context.h" #include "mongo/scripting/engine.h" #include "mongo/util/startup_test.h" namespace mongo { NamespaceDetails::NamespaceDetails( const DiskLoc &loc, bool capped ) { BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(NamespaceDetails) ); /* be sure to initialize new fields here -- doesn't default to zeroes the way we use it */ firstExtent = lastExtent = capExtent = loc; stats.datasize = stats.nrecords = 0; lastExtentSize = 0; nIndexes = 0; isCapped = capped; maxDocsInCapped = 0x7fffffff; // no limit (value is for pre-v2.3.2 compatibility) paddingFactorOldDoNotUse = 1.0; systemFlagsOldDoNotUse = 0; userFlags = 0; capFirstNewRecord = DiskLoc(); // Signal that we are on first allocation iteration through extents. capFirstNewRecord.setInvalid(); // For capped case, signal that we are doing initial extent allocation. if ( capped ) { // WAS: cappedLastDelRecLastExtent().setInvalid(); deletedListSmall[1].setInvalid(); } verify( sizeof(_dataFileVersion) == 2 ); _dataFileVersion = 0; _indexFileVersion = 0; multiKeyIndexBits = 0; _reservedA = 0; _extraOffset = 0; indexBuildsInProgress = 0; memset(_reserved, 0, sizeof(_reserved)); } NamespaceDetails::Extra* NamespaceDetails::allocExtra( OperationContext* txn, const StringData& ns, NamespaceIndex& ni, int nindexessofar) { // Namespace details must always be changed under an exclusive DB lock const NamespaceString nss(ns); invariant(txn->lockState()->isDbLockedForMode(nss.db(), MODE_X)); int i = (nindexessofar - NIndexesBase) / NIndexesExtra; verify( i >= 0 && i <= 1 ); Namespace fullns( ns ); Namespace extrans( fullns.extraName(i) ); // throws UserException if ns name too long massert( 10350, "allocExtra: base ns missing?", this ); massert( 10351, "allocExtra: extra already exists", ni.details(extrans) == 0 ); Extra temp; temp.init(); ni.add_ns( txn, extrans, reinterpret_cast( &temp ) ); Extra* e = reinterpret_cast( ni.details( extrans ) ); long ofs = e->ofsFrom(this); if( i == 0 ) { verify( _extraOffset == 0 ); *txn->recoveryUnit()->writing(&_extraOffset) = ofs; verify( extra() == e ); } else { Extra *hd = extra(); verify( hd->next(this) == 0 ); hd->setNext(txn, ofs); } return e; } IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) { if( idxNo < NIndexesBase ) { IndexDetails& id = _indexes[idxNo]; return id; } Extra *e = extra(); if ( ! e ) { if ( missingExpected ) throw MsgAssertionException( 13283 , "Missing Extra" ); massert(14045, "missing Extra", e); } int i = idxNo - NIndexesBase; if( i >= NIndexesExtra ) { e = e->next(this); if ( ! e ) { if ( missingExpected ) throw MsgAssertionException( 14823 , "missing extra" ); massert(14824, "missing Extra", e); } i -= NIndexesExtra; } return e->details[i]; } const IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) const { if( idxNo < NIndexesBase ) { const IndexDetails& id = _indexes[idxNo]; return id; } const Extra *e = extra(); if ( ! e ) { if ( missingExpected ) throw MsgAssertionException( 17421 , "Missing Extra" ); massert(17422, "missing Extra", e); } int i = idxNo - NIndexesBase; if( i >= NIndexesExtra ) { e = e->next(this); if ( ! e ) { if ( missingExpected ) throw MsgAssertionException( 17423 , "missing extra" ); massert(17424, "missing Extra", e); } i -= NIndexesExtra; } return e->details[i]; } NamespaceDetails::IndexIterator::IndexIterator(const NamespaceDetails *_d, bool includeBackgroundInProgress) { d = _d; i = 0; n = d->nIndexes; if ( includeBackgroundInProgress ) n += d->indexBuildsInProgress; } // must be called when renaming a NS to fix up extra void NamespaceDetails::copyingFrom( OperationContext* txn, const StringData& thisns, NamespaceIndex& ni, NamespaceDetails* src) { _extraOffset = 0; // we are a copy -- the old value is wrong. fixing it up below. Extra *se = src->extra(); int n = NIndexesBase; if( se ) { Extra *e = allocExtra(txn, thisns, ni, n); while( 1 ) { n += NIndexesExtra; e->copy(this, *se); se = se->next(src); if( se == 0 ) break; Extra *nxt = allocExtra(txn, thisns, ni, n); e->setNext( txn, nxt->ofsFrom(this) ); e = nxt; } verify( _extraOffset ); } } NamespaceDetails* NamespaceDetails::writingWithoutExtra( OperationContext* txn ) { return txn->recoveryUnit()->writing( this ); } // XXX - this method should go away NamespaceDetails *NamespaceDetails::writingWithExtra( OperationContext* txn ) { for( Extra *e = extra(); e; e = e->next( this ) ) { txn->recoveryUnit()->writing( e ); } return writingWithoutExtra( txn ); } void NamespaceDetails::setMaxCappedDocs( OperationContext* txn, long long max ) { massert( 16499, "max in a capped collection has to be < 2^31 or -1", CollectionOptions::validMaxCappedDocs( &max ) ); maxDocsInCapped = max; } /* ------------------------------------------------------------------------- */ int NamespaceDetails::_catalogFindIndexByName(OperationContext* txn, const Collection* coll, const StringData& name, bool includeBackgroundInProgress) const { IndexIterator i = ii(includeBackgroundInProgress); while( i.more() ) { const BSONObj obj = coll->docFor(txn, i.next().info.toRecordId()).value(); if ( name == obj.getStringField("name") ) return i.pos()-1; } return -1; } void NamespaceDetails::Extra::setNext( OperationContext* txn, long ofs ) { *txn->recoveryUnit()->writing(&_next) = ofs; } } // namespace mongo