// database.h /** * 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 . */ /* Database represents a database database Each database database has its own set of files -- dbname.ns, dbname.0, dbname.1, ... */ class Database { public: Database(const char *nm, bool& justCreated) : name(nm) { justCreated = namespaceIndex.init(dbpath, nm); profile = 0; profileName = name + ".system.profile"; } ~Database() { int n = files.size(); for( int i = 0; i < n; i++ ) delete files[i]; } PhysicalDataFile* getFile(int n) { assert(this); if( n < 0 || n >= DiskLoc::MaxFiles ) { cout << "getFile(): n=" << n << endl; assert( n >= 0 && n < DiskLoc::MaxFiles ); } DEV { if( n > 100 ) cout << "getFile(): n=" << n << "?" << endl; } while( n >= (int) files.size() ) files.push_back(0); PhysicalDataFile* p = files[n]; if( p == 0 ) { p = new PhysicalDataFile(n); files[n] = p; stringstream out; out << dbpath << name << '.' << n; p->open(n, out.str().c_str()); } return p; } PhysicalDataFile* addAFile() { int n = (int) files.size(); return getFile(n); } PhysicalDataFile* suitableFile(int sizeNeeded) { PhysicalDataFile* f = newestFile(); for( int i = 0; i < 8; i++ ) { if( f->getHeader()->unusedLength >= sizeNeeded ) break; f = addAFile(); if( f->getHeader()->fileLength > 1500000000 ) // this is as big as they get so might as well stop break; } return f; } PhysicalDataFile* newestFile() { int n = (int) files.size(); if( n > 0 ) n--; return getFile(n); } void finishInit(); // ugly... vector files; string name; // "alleyinsider" NamespaceIndex namespaceIndex; int profile; // 0=off. string profileName; // "alleyinsider.system.profile" QueryOptimizer optimizer; bool haveLogged() { return _haveLogged; } void setHaveLogged(); private: // see dbinfo.h description. if true, we have logged to the replication log. bool _haveLogged; }; // tempish...move to TLS or pass all the way down as a parm extern map databases; extern Database *database; extern const char *curNs; extern int dbLocked; extern bool master; /* returns true if the database ("database") did not exist, and it was created on this call */ inline bool setClient(const char *ns) { /* we must be in critical section at this point as these are global variables. */ assert( dbLocked == 1 ); char cl[256]; curNs = ns; nsToClient(ns, cl); map::iterator it = databases.find(cl); if( it != databases.end() ) { database = it->second; return false; } // when master for replication, we advertise all the db's, and that // looks like a 'first operation'. so that breaks this log message's // meaningfulness. instead of fixing (which would be better), we just // stop showing for now. if( !master ) log() << "first operation for database " << cl << endl; bool justCreated; Database *c = new Database(cl, justCreated); databases[cl] = c; database = c; database->finishInit(); return justCreated; } /* We normally keep around a curNs ptr -- if this ns is temporary, use this instead so we don't have a bad ptr. we could have made a copy, but trying to be fast as we call setClient this for every single operation. */ inline bool setClientTempNs(const char *ns) { bool jc = setClient(ns); curNs = ""; return jc; } #include "dbinfo.h"