summaryrefslogtreecommitdiff
path: root/src/mongo/db/introspect.cpp
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-01-13 14:58:50 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2015-01-15 10:41:43 -0500
commit02a78a7f3d936813ea9e4195887b11d83448fcd6 (patch)
tree225019d9b28e394dfe141a3bb5a50217f8ee50ef /src/mongo/db/introspect.cpp
parentd3ed3fad57e35f2459660c05b37e3b0509e45e5c (diff)
downloadmongo-02a78a7f3d936813ea9e4195887b11d83448fcd6.tar.gz
SERVER-16431 Simplify DB profile code
Diffstat (limited to 'src/mongo/db/introspect.cpp')
-rw-r--r--src/mongo/db/introspect.cpp229
1 files changed, 97 insertions, 132 deletions
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp
index 890836e6c2f..f90dec52159 100644
--- a/src/mongo/db/introspect.cpp
+++ b/src/mongo/db/introspect.cpp
@@ -1,48 +1,43 @@
-// introspect.cpp
-
/**
-* 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 <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.
-*/
+ * Copyright (C) 2008 MongoDB 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.
+ */
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
#include "mongo/platform/basic.h"
-#include <boost/scoped_ptr.hpp>
+#include "mongo/db/introspect.h"
#include "mongo/bson/util/builder.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/auth/user_set.h"
#include "mongo/db/curop.h"
-#include "mongo/db/catalog/database_holder.h"
-#include "mongo/db/introspect.h"
#include "mongo/db/jsobj.h"
-#include "mongo/db/storage_options.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/util/log.h"
@@ -53,6 +48,7 @@ namespace mongo {
using std::string;
namespace {
+
void _appendUserInfo(const CurOp& c,
BSONObjBuilder& builder,
AuthorizationSession* authSession) {
@@ -80,141 +76,110 @@ namespace {
builder.append("user", bestUser.getUser().empty() ? "" : bestUser.getFullName());
}
+
} // namespace
- /**
- * @return if collection existed or was created
- */
- static bool _profile(OperationContext* txn,
- const Client& c,
- Database* db,
- CurOp& currentOp,
- BufBuilder& profileBufBuilder) {
- dassert( db );
-
- // build object
+
+ void profile(OperationContext* txn, int op) {
+ // Initialize with 1kb at start in order to avoid realloc later
+ BufBuilder profileBufBuilder(1024);
+
BSONObjBuilder b(profileBufBuilder);
- currentOp.debug().append(currentOp, b);
+ txn->getCurOp()->debug().append(*txn->getCurOp(), b);
b.appendDate("ts", jsTime());
- b.append("client", c.clientAddress());
+ b.append("client", txn->getClient()->clientAddress());
- AuthorizationSession * authSession = c.getAuthorizationSession();
- _appendUserInfo(currentOp, b, authSession);
+ AuthorizationSession * authSession = txn->getClient()->getAuthorizationSession();
+ _appendUserInfo(*txn->getCurOp(), b, authSession);
BSONObj p = b.done();
- WriteUnitOfWork wunit(txn);
+ const string dbName(nsToDatabase(txn->getCurOp()->getNS()));
- // write: not replicated
- // get or create the profiling collection
- Collection* profileCollection = getOrCreateProfileCollection(txn, db);
- if ( !profileCollection ) {
- return false;
- }
- profileCollection->insertDocument( txn, p, false );
- wunit.commit();
- return true;
- }
+ try {
+ bool acquireDbXLock = false;
+ while (true) {
+ ScopedTransaction scopedXact(txn, MODE_IX);
- void profile(OperationContext* txn, const Client& c, int op, CurOp& currentOp) {
- bool tryAgain = false;
- while ( 1 ) {
- try {
- // initialize with 1kb to start, to avoid realloc later
- // doing this outside the dblock to improve performance
- BufBuilder profileBufBuilder(1024);
-
- // NOTE: It's kind of weird that we lock the op's namespace, but have to for now
- // since we're sometimes inside the lock already
- const string dbname(nsToDatabase(currentOp.getNS()));
- scoped_ptr<Lock::DBLock> lk;
-
- // todo: this can be slow, perhaps can re-work
- if ( !txn->lockState()->isDbLockedForMode( dbname, MODE_IX ) ) {
- lk.reset( new Lock::DBLock( txn->lockState(),
- dbname,
- tryAgain ? MODE_X : MODE_IX) );
- }
- Database* db = dbHolder().get(txn, dbname);
- if (db != NULL) {
- Lock::CollectionLock clk(txn->lockState(), db->getProfilingNS(), MODE_X);
- Client::Context cx(txn, currentOp.getNS(), false);
- if ( !_profile(txn, c, cx.db(), currentOp, profileBufBuilder ) && lk.get() ) {
- if ( tryAgain ) {
- // we couldn't profile, but that's ok, we should have logged already
- break;
- }
- // we took an IX lock, so now we try again with an X lock
- tryAgain = true;
- continue;
+ boost::scoped_ptr<AutoGetDb> autoGetDb;
+ if (acquireDbXLock) {
+ autoGetDb.reset(new AutoGetDb(txn, dbName, MODE_X));
+ if (autoGetDb->getDb()) {
+ createProfileCollection(txn, autoGetDb->getDb());
}
}
else {
- mongo::log() << "note: not profiling because db went away - "
- << "probably a close on: " << currentOp.getNS();
+ autoGetDb.reset(new AutoGetDb(txn, dbName, MODE_IX));
+ }
+
+ Database* const db = autoGetDb->getDb();
+ if (!db) {
+ // Database disappeared
+ log() << "note: not profiling because db went away for "
+ << txn->getCurOp()->getNS();
+ break;
+ }
+
+ Lock::CollectionLock collLock(txn->lockState(), db->getProfilingNS(), MODE_IX);
+
+ Collection* const coll = db->getCollection(db->getProfilingNS());
+ if (coll) {
+ WriteUnitOfWork wuow(txn);
+ coll->insertDocument(txn, p, false);
+ wuow.commit();
+
+ break;
+ }
+ else if (!acquireDbXLock && !txn->lockState()->isLocked()) {
+ // Try to create the collection only if we are not under lock, in order to
+ // avoid deadlocks due to lock conversion. This would only be hit if someone
+ // deletes the profiler collection after setting profile level.
+ acquireDbXLock = true;
+ }
+ else {
+ // Cannot write the profile information
+ break;
}
- return;
- }
- catch (const AssertionException& assertionEx) {
- warning() << "Caught Assertion while trying to profile " << opToString(op)
- << " against " << currentOp.getNS()
- << ": " << assertionEx.toString() << endl;
- return;
}
}
+ catch (const AssertionException& assertionEx) {
+ warning() << "Caught Assertion while trying to profile "
+ << opToString(op)
+ << " against " << txn->getCurOp()->getNS()
+ << ": " << assertionEx.toString() << endl;
+ }
}
- Collection* getOrCreateProfileCollection(OperationContext* txn,
- Database *db,
- bool force,
- string* errmsg ) {
- fassert(16372, db);
- const char* profileName = db->getProfilingNS();
- Collection* collection = db->getCollection( profileName );
-
- if ( collection ) {
- if ( !collection->isCapped() ) {
- string myerrmsg = str::stream() << profileName << " exists but isn't capped";
- log() << myerrmsg << endl;
- if ( errmsg )
- *errmsg = myerrmsg;
- return NULL;
- }
- return collection;
- }
- // does not exist!
+ Status createProfileCollection(OperationContext* txn, Database *db) {
+ invariant(txn->lockState()->isDbLockedForMode(db->name(), MODE_X));
+
+ const std::string dbProfilingNS(db->getProfilingNS());
- if ( force == false && serverGlobalParams.defaultProfile == false ) {
- // we don't want it, so why are we here?
- static time_t last = time(0) - 10; // warn the first time
- if( time(0) > last+10 ) {
- log() << "profile: warning ns " << profileName << " does not exist" << endl;
- last = time(0);
+ Collection* const collection = db->getCollection(dbProfilingNS);
+ if (collection) {
+ if (!collection->isCapped()) {
+ return Status(ErrorCodes::NamespaceExists,
+ str::stream() << dbProfilingNS << " exists but isn't capped");
}
- return NULL;
- }
- if ( !txn->lockState()->isDbLockedForMode( db->name(), MODE_X ) ) {
- // can't create here
- return NULL;
+ return Status::OK();
}
// system.profile namespace doesn't exist; create it
- log() << "creating profile collection: " << profileName << endl;
+ log() << "Creating profile collection: " << dbProfilingNS << endl;
CollectionOptions collectionOptions;
collectionOptions.capped = true;
collectionOptions.cappedSize = 1024 * 1024;
WriteUnitOfWork wunit(txn);
- collection = db->createCollection( txn, profileName, collectionOptions );
- invariant( collection );
+ invariant(db->createCollection(txn, dbProfilingNS, collectionOptions));
wunit.commit();
- return collection;
+ return Status::OK();
}
} // namespace mongo