diff options
Diffstat (limited to 'src/mongo/db/structure/catalog/namespace_index.cpp')
| -rw-r--r-- | src/mongo/db/structure/catalog/namespace_index.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/src/mongo/db/structure/catalog/namespace_index.cpp b/src/mongo/db/structure/catalog/namespace_index.cpp new file mode 100644 index 00000000000..803570fc66d --- /dev/null +++ b/src/mongo/db/structure/catalog/namespace_index.cpp @@ -0,0 +1,227 @@ +// namespace_index.cpp + +/** + * Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. + * + * 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/db/structure/catalog/namespace_index.h" + +#include <boost/filesystem/operations.hpp> + +#include "mongo/db/structure/catalog/namespace_details.h" +#include "mongo/util/file.h" + + +namespace mongo { + + NamespaceDetails* NamespaceIndex::details(const StringData& ns) { + Namespace n(ns); + return details(n); + } + + NamespaceDetails* NamespaceIndex::details(const Namespace& ns) { + if ( !_ht.get() ) + return 0; + NamespaceDetails *d = _ht->get(ns); + if ( d && d->isCapped() ) + d->cappedCheckMigrate(); + return d; + } + + void NamespaceIndex::add_ns(const StringData& ns, const DiskLoc& loc, bool capped) { + NamespaceDetails details( loc, capped ); + add_ns( ns, &details ); + } + + void NamespaceIndex::add_ns( const StringData& ns, const NamespaceDetails* details ) { + Namespace n(ns); + add_ns( n, details ); + } + + void NamespaceIndex::add_ns( const Namespace& ns, const NamespaceDetails* details ) { + 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)); + } + + void NamespaceIndex::kill_ns(const StringData& ns) { + Lock::assertWriteLocked(ns); + if ( !_ht.get() ) + return; + Namespace n(ns); + _ht->kill(n); + + if (ns.size() <= Namespace::MaxNsColletionLen) { + // Larger namespace names don't have room for $extras so they can't exist. The code + // below would cause an "$extra: ns too large" error and stacktrace to be printed to the + // log even though everything is fine. + for( int i = 0; i<=1; i++ ) { + try { + Namespace extra(n.extraName(i)); + _ht->kill(extra); + } + catch(DBException&) { + MONGO_DLOG(3) << "caught exception in kill_ns" << endl; + } + } + } + } + + bool NamespaceIndex::exists() const { + return !boost::filesystem::exists(path()); + } + + boost::filesystem::path NamespaceIndex::path() const { + boost::filesystem::path ret( _dir ); + if (storageGlobalParams.directoryperdb) + ret /= _database; + ret /= ( _database + ".ns" ); + return ret; + } + + static void namespaceGetNamespacesCallback( const Namespace& k , NamespaceDetails& v , void * extra ) { + list<string> * l = (list<string>*)extra; + if ( ! k.hasDollarSign() || k == "local.oplog.$main" ) { + // we call out local.oplog.$main specifically as its the only "normal" + // collection that has a $, so we make sure it gets added + l->push_back( (string)k ); + } + } + + void NamespaceIndex::getNamespaces( list<string>& tofill , bool onlyCollections ) const { + verify( onlyCollections ); // TODO: need to implement this + // need boost::bind or something to make this less ugly + + if ( _ht.get() ) + _ht->iterAll( namespaceGetNamespacesCallback , (void*)&tofill ); + } + + void NamespaceIndex::maybeMkdir() const { + if (!storageGlobalParams.directoryperdb) + return; + boost::filesystem::path dir( _dir ); + dir /= _database; + if ( !boost::filesystem::exists( dir ) ) + MONGO_ASSERT_ON_EXCEPTION_WITH_MSG( boost::filesystem::create_directory( dir ), "create dir for db " ); + } + + NOINLINE_DECL void NamespaceIndex::_init() { + verify( !_ht.get() ); + + Lock::assertWriteLocked(_database); + + /* if someone manually deleted the datafiles for a database, + we need to be sure to clear any cached info for the database in + local.*. + */ + /* + if ( "local" != _database ) { + DBInfo i(_database.c_str()); + i.dbDropped(); + } + */ + + unsigned long long len = 0; + boost::filesystem::path nsPath = path(); + string pathString = nsPath.string(); + void *p = 0; + if ( boost::filesystem::exists(nsPath) ) { + if( _f.open(pathString, true) ) { + len = _f.length(); + if ( len % (1024*1024) != 0 ) { + log() << "bad .ns file: " << pathString << endl; + uassert( 10079 , "bad .ns file length, cannot open database", len % (1024*1024) == 0 ); + } + p = _f.getView(); + } + } + else { + // use storageGlobalParams.lenForNewNsFiles, we are making a new database + massert(10343, "bad storageGlobalParams.lenForNewNsFiles", + storageGlobalParams.lenForNewNsFiles >= 1024*1024); + maybeMkdir(); + unsigned long long l = storageGlobalParams.lenForNewNsFiles; + log() << "allocating new ns file " << pathString << ", filling with zeroes..." << endl; + + { + // Due to SERVER-15369 we need to explicitly write zero-bytes to the NS file. + const unsigned long long kBlockSize = 1024*1024; + invariant(l % kBlockSize == 0); // ns files can only be multiples of 1MB + const std::vector<char> zeros(kBlockSize, 0); + + File file; + file.open(pathString.c_str()); + massert(18825, str::stream() << "couldn't create file " << pathString, file.is_open()); + for (fileofs ofs = 0; ofs < l && !file.bad(); ofs += kBlockSize ) { + file.write(ofs, &zeros[0], kBlockSize); + } + if (file.bad()) { + try { + boost::filesystem::remove(pathString); + } catch (const std::exception& e) { + StringBuilder ss; + ss << "error removing file: " << e.what(); + massert(18909, ss.str(), 0); + } + } + else { + file.fsync(); + } + massert(18826, str::stream() << "failure writing file " << pathString, !file.bad() ); + } + + if ( _f.create(pathString, l, true) ) { + getDur().createdFile(pathString, l); // always a new file + len = l; + verify(len == storageGlobalParams.lenForNewNsFiles); + p = _f.getView(); + + if ( p ) { + // we do this so the durability system isn't mad at us for + // only initiating file and not doing a write + // grep for 17388 + getDur().writingPtr( p, 5 ); // throw away + } + } + } + + if ( p == 0 ) { + /** TODO: this shouldn't terminate? */ + log() << "error couldn't open file " << pathString << " terminating" << endl; + dbexit( EXIT_FS ); + } + + + verify( len <= 0x7fffffff ); + _ht.reset(new HashTable<Namespace,NamespaceDetails>(p, (int) len, "namespace index")); + } + + +} + |
