summaryrefslogtreecommitdiff
path: root/src/mongo/db/service_context_d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/service_context_d.cpp')
-rw-r--r--src/mongo/db/service_context_d.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/src/mongo/db/service_context_d.cpp b/src/mongo/db/service_context_d.cpp
new file mode 100644
index 00000000000..4c3d30032df
--- /dev/null
+++ b/src/mongo/db/service_context_d.cpp
@@ -0,0 +1,275 @@
+/**
+ * Copyright (C) 2014 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/db/service_context_d.h"
+
+#include "mongo/base/init.h"
+#include "mongo/base/initializer.h"
+#include "mongo/db/client.h"
+#include "mongo/db/curop.h"
+#include "mongo/db/op_observer.h"
+#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage/storage_engine.h"
+#include "mongo/db/storage/storage_engine_lock_file.h"
+#include "mongo/db/storage/storage_engine_metadata.h"
+#include "mongo/db/storage_options.h"
+#include "mongo/scripting/engine.h"
+#include "mongo/stdx/memory.h"
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+#include "mongo/util/scopeguard.h"
+
+namespace mongo {
+
+ MONGO_INITIALIZER(SetGlobalEnvironment)(InitializerContext* context) {
+ setGlobalServiceContext(stdx::make_unique<ServiceContextMongoD>());
+ return Status::OK();
+ }
+
+ ServiceContextMongoD::ServiceContextMongoD()
+ : _globalKill(false),
+ _storageEngine(NULL) { }
+
+ ServiceContextMongoD::~ServiceContextMongoD() {
+
+ }
+
+ StorageEngine* ServiceContextMongoD::getGlobalStorageEngine() {
+ // We don't check that globalStorageEngine is not-NULL here intentionally. We can encounter
+ // an error before it's initialized and proceed to exitCleanly which is equipped to deal
+ // with a NULL storage engine.
+ return _storageEngine;
+ }
+
+ extern bool _supportsDocLocking;
+
+ void ServiceContextMongoD::setGlobalStorageEngine(const std::string& name) {
+ // This should be set once.
+ invariant(!_storageEngine);
+
+ const StorageEngine::Factory* factory = _storageFactories[name];
+
+ uassert(18656, str::stream()
+ << "Cannot start server with an unknown storage engine: " << name,
+ factory);
+
+ std::string canonicalName = factory->getCanonicalName().toString();
+
+ // Do not proceed if data directory has been used by a different storage engine previously.
+ std::auto_ptr<StorageEngineMetadata> metadata =
+ StorageEngineMetadata::validate(storageGlobalParams.dbpath, canonicalName);
+
+ // Validate options in metadata against current startup options.
+ if (metadata.get()) {
+ uassertStatusOK(factory->validateMetadata(*metadata, storageGlobalParams));
+ }
+
+ try {
+ _lockFile.reset(new StorageEngineLockFile(storageGlobalParams.dbpath));
+ }
+ catch (const std::exception& ex) {
+ uassert(28596, str::stream()
+ << "Unable to determine status of lock file in the data directory "
+ << storageGlobalParams.dbpath << ": " << ex.what(),
+ false);
+ }
+ if (_lockFile->createdByUncleanShutdown()) {
+ warning() << "Detected unclean shutdown - "
+ << _lockFile->getFilespec() << " is not empty.";
+ }
+ uassertStatusOK(_lockFile->open());
+
+ ScopeGuard guard = MakeGuard(&StorageEngineLockFile::close, _lockFile.get());
+ _storageEngine = factory->create(storageGlobalParams, *_lockFile);
+ _storageEngine->finishInit();
+ uassertStatusOK(_lockFile->writePid());
+
+ // Write a new metadata file if it is not present.
+ if (!metadata.get()) {
+ metadata.reset(new StorageEngineMetadata(storageGlobalParams.dbpath));
+ metadata->setStorageEngine(canonicalName);
+ metadata->setStorageEngineOptions(factory->createMetadataOptions(storageGlobalParams));
+ uassertStatusOK(metadata->write());
+ }
+
+ guard.Dismiss();
+
+ _supportsDocLocking = _storageEngine->supportsDocLocking();
+ }
+
+ void ServiceContextMongoD::shutdownGlobalStorageEngineCleanly() {
+ invariant(_storageEngine);
+ invariant(_lockFile.get());
+ _storageEngine->cleanShutdown();
+ _lockFile->clearPidAndUnlock();
+ }
+
+ void ServiceContextMongoD::registerStorageEngine(const std::string& name,
+ const StorageEngine::Factory* factory) {
+ // No double-registering.
+ invariant(0 == _storageFactories.count(name));
+
+ // Some sanity checks: the factory must exist,
+ invariant(factory);
+
+ // and all factories should be added before we pick a storage engine.
+ invariant(NULL == _storageEngine);
+
+ _storageFactories[name] = factory;
+ }
+
+ bool ServiceContextMongoD::isRegisteredStorageEngine(const std::string& name) {
+ return _storageFactories.count(name);
+ }
+
+ StorageFactoriesIterator* ServiceContextMongoD::makeStorageFactoriesIterator() {
+ return new StorageFactoriesIteratorMongoD(_storageFactories.begin(),
+ _storageFactories.end());
+ }
+
+ StorageFactoriesIteratorMongoD::StorageFactoriesIteratorMongoD(
+ const ServiceContextMongoD::FactoryMap::const_iterator& begin,
+ const ServiceContextMongoD::FactoryMap::const_iterator& end) :
+ _curr(begin), _end(end) {
+ }
+
+ bool StorageFactoriesIteratorMongoD::more() const {
+ return _curr != _end;
+ }
+
+ const StorageEngine::Factory* StorageFactoriesIteratorMongoD::next() {
+ return _curr++->second;
+ }
+
+ void ServiceContextMongoD::setKillAllOperations() {
+ boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
+ _globalKill = true;
+ for (size_t i = 0; i < _killOpListeners.size(); i++) {
+ try {
+ _killOpListeners[i]->interruptAll();
+ }
+ catch (...) {
+ std::terminate();
+ }
+ }
+ }
+
+ bool ServiceContextMongoD::getKillAllOperations() {
+ return _globalKill;
+ }
+
+ bool ServiceContextMongoD::_killOperationsAssociatedWithClientAndOpId_inlock(
+ Client* client, unsigned int opId) {
+ for( CurOp *k = client->curop(); k; k = k->parent() ) {
+ if ( k->opNum() != opId )
+ continue;
+
+ k->kill();
+ for( CurOp *l = client->curop(); l; l = l->parent() ) {
+ l->kill();
+ }
+
+ for (size_t i = 0; i < _killOpListeners.size(); i++) {
+ try {
+ _killOpListeners[i]->interrupt(opId);
+ }
+ catch (...) {
+ std::terminate();
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ bool ServiceContextMongoD::killOperation(unsigned int opId) {
+ boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
+
+ for(ClientSet::const_iterator j = Client::clients.begin();
+ j != Client::clients.end(); ++j) {
+
+ Client* client = *j;
+
+ bool found = _killOperationsAssociatedWithClientAndOpId_inlock(client, opId);
+ if (found) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void ServiceContextMongoD::killAllUserOperations(const OperationContext* txn) {
+ boost::lock_guard<boost::mutex> scopedLock(Client::clientsMutex);
+ for (ClientSet::const_iterator i = Client::clients.begin();
+ i != Client::clients.end(); i++) {
+
+ Client* client = *i;
+ if (!client->isFromUserConnection()) {
+ // Don't kill system operations.
+ continue;
+ }
+
+ if (client->curop()->opNum() == txn->getOpID()) {
+ // Don't kill ourself.
+ continue;
+ }
+
+ bool found = _killOperationsAssociatedWithClientAndOpId_inlock(
+ client, client->curop()->opNum());
+ if (!found) {
+ warning() << "Attempted to kill operation " << client->curop()->opNum()
+ << " but the opId changed";
+ }
+ }
+ }
+
+ void ServiceContextMongoD::unsetKillAllOperations() {
+ _globalKill = false;
+ }
+
+ void ServiceContextMongoD::registerKillOpListener(KillOpListenerInterface* listener) {
+ boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
+ _killOpListeners.push_back(listener);
+ }
+
+ OperationContext* ServiceContextMongoD::newOpCtx() {
+ return new OperationContextImpl();
+ }
+
+ void ServiceContextMongoD::setOpObserver(std::unique_ptr<OpObserver> opObserver) {
+ _opObserver.reset(opObserver.get());
+ }
+
+ OpObserver* ServiceContextMongoD::getOpObserver() {
+ return _opObserver.get();
+ }
+
+} // namespace mongo