summaryrefslogtreecommitdiff
path: root/src/mongo/db/introspect.cpp
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-12-17 18:10:39 -0500
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2014-12-17 18:10:39 -0500
commit8d90ce21ffb7fac21fd9f287ce3d66a4c6b576b8 (patch)
treec7e199fe9f15094efd7f45234b432a2d40a02308 /src/mongo/db/introspect.cpp
parentf46ff140de92e43c34bace43be971fd903ac11d9 (diff)
downloadmongo-8d90ce21ffb7fac21fd9f287ce3d66a4c6b576b8.tar.gz
Revert "SERVER-16431 Simplify DB profile code"
This reverts commit c5ebc6be8e3a865655acbc5ecd1cb3b96fdf44ff.
Diffstat (limited to 'src/mongo/db/introspect.cpp')
-rw-r--r--src/mongo/db/introspect.cpp233
1 files changed, 134 insertions, 99 deletions
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp
index 65a5bee8c86..6dd6c323a99 100644
--- a/src/mongo/db/introspect.cpp
+++ b/src/mongo/db/introspect.cpp
@@ -1,49 +1,53 @@
+// introspect.cpp
+
/**
- * 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.
- */
+* 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.
+*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/introspect.h"
+#include "mongo/pch.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/goodies.h"
#include "mongo/util/log.h"
namespace mongo {
-namespace {
+namespace {
void _appendUserInfo(const CurOp& c,
BSONObjBuilder& builder,
AuthorizationSession* authSession) {
@@ -71,110 +75,141 @@ namespace {
builder.append("user", bestUser.getUser().empty() ? "" : bestUser.getFullName());
}
-
} // namespace
-
- void profile(OperationContext* txn, int op) {
- // initialize with 1kb to start, to avoid realloc later
- BufBuilder profileBufBuilder(1024);
-
+ /**
+ * @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
BSONObjBuilder b(profileBufBuilder);
- txn->getCurOp()->debug().append(*txn->getCurOp(), b);
+ currentOp.debug().append(currentOp, b);
b.appendDate("ts", jsTime());
- b.append("client", txn->getClient()->clientAddress());
+ b.append("client", c.clientAddress());
- AuthorizationSession * authSession = txn->getClient()->getAuthorizationSession();
- _appendUserInfo(*txn->getCurOp(), b, authSession);
+ AuthorizationSession * authSession = c.getAuthorizationSession();
+ _appendUserInfo(currentOp, b, authSession);
BSONObj p = b.done();
- const string dbName(nsToDatabase(txn->getCurOp()->getNS()));
-
- try {
- bool acquireDbXLock = false;
- while (true) {
- ScopedTransaction scopedXact(txn, MODE_IX);
-
- boost::scoped_ptr<AutoGetDb> autoGetDb;
- if (acquireDbXLock) {
- autoGetDb.reset(new AutoGetDb(txn, dbName, MODE_X));
- if (autoGetDb->getDb()) {
- createProfileCollection(txn, autoGetDb->getDb());
- }
- }
- else {
- 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);
+ WriteUnitOfWork wunit(txn);
- Collection* const coll = db->getCollection(txn, db->getProfilingNS());
- if (coll) {
- WriteUnitOfWork wuow(txn);
- coll->insertDocument(txn, p, false);
- wuow.commit();
+ // 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;
+ }
- break;
+ 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) );
}
- 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;
+ 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;
+ }
}
else {
- // Cannot write the profile information
- break;
+ mongo::log() << "note: not profiling because db went away - "
+ << "probably a close on: " << currentOp.getNS();
}
+ 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( txn, 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;
+ }
- Status createProfileCollection(OperationContext* txn, Database *db) {
- invariant(txn->lockState()->isDbLockedForMode(db->name(), MODE_X));
-
- const std::string dbProfilingNS(db->getProfilingNS());
+ // does not exist!
- Collection* const collection = db->getCollection(txn, dbProfilingNS);
- if (collection) {
- if (!collection->isCapped()) {
- return Status(ErrorCodes::NamespaceExists,
- str::stream() << dbProfilingNS << " exists but isn't capped");
+ 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);
}
+ return NULL;
+ }
- return Status::OK();
+ if ( !txn->lockState()->isDbLockedForMode( db->name(), MODE_X ) ) {
+ // can't create here
+ return NULL;
}
// system.profile namespace doesn't exist; create it
- log() << "Creating profile collection: " << dbProfilingNS << endl;
+ log() << "creating profile collection: " << profileName << endl;
CollectionOptions collectionOptions;
collectionOptions.capped = true;
collectionOptions.cappedSize = 1024 * 1024;
WriteUnitOfWork wunit(txn);
- invariant(db->createCollection(txn, dbProfilingNS, collectionOptions));
+ collection = db->createCollection( txn, profileName, collectionOptions );
+ invariant( collection );
wunit.commit();
- return Status::OK();
+ return collection;
}
} // namespace mongo