summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2016-04-04 19:01:43 -0400
committerAndy Schwerin <schwerin@mongodb.com>2016-04-07 11:32:38 -0400
commit5f23fb00bf69a19b67c385e7e953137c70eaa3e0 (patch)
treedc3635ecfa30af793d571261524b2feb16a62723 /src
parent0953a237e58d2af33a55c420d8aefbbb3d4ff88b (diff)
downloadmongo-5f23fb00bf69a19b67c385e7e953137c70eaa3e0.tar.gz
SERVER-23299 When starting mongod, clear temp flags from collections if appropriate.
See the description in SERVER-23299 for the definition of appropriate. (cherry picked from commit 5e11e4484b84c8f913a4b14b24fbb7c9c46ee40f)
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/catalog/collection_catalog_entry.h5
-rw-r--r--src/mongo/db/db.cpp93
-rw-r--r--src/mongo/db/storage/kv/kv_collection_catalog_entry.cpp6
-rw-r--r--src/mongo/db/storage/kv/kv_collection_catalog_entry.h2
-rw-r--r--src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp4
-rw-r--r--src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h2
6 files changed, 106 insertions, 6 deletions
diff --git a/src/mongo/db/catalog/collection_catalog_entry.h b/src/mongo/db/catalog/collection_catalog_entry.h
index e1261e6a409..a31843b3cce 100644
--- a/src/mongo/db/catalog/collection_catalog_entry.h
+++ b/src/mongo/db/catalog/collection_catalog_entry.h
@@ -98,6 +98,11 @@ public:
virtual void updateFlags(OperationContext* txn, int newValue) = 0;
/**
+ * Clears the "temp" flag from the CollectionOptions of this collection.
+ */
+ virtual void clearTempFlag(OperationContext* txn) = 0;
+
+ /**
* Updates the validator for this collection.
*
* An empty validator removes all validation.
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 583907c6619..b49310a0046 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -48,6 +48,7 @@
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global.h"
#include "mongo/db/catalog/collection.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/catalog/database_catalog_entry.h"
#include "mongo/db/catalog/database_holder.h"
@@ -56,8 +57,11 @@
#include "mongo/db/client.h"
#include "mongo/db/clientcursor.h"
#include "mongo/db/concurrency/d_concurrency.h"
+#include "mongo/db/concurrency/lock_state.h"
+#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
+#include "mongo/db/dbhelpers.h"
#include "mongo/db/dbmessage.h"
#include "mongo/db/dbwebserver.h"
#include "mongo/db/ftdc/ftdc_mongod.h"
@@ -145,6 +149,8 @@ void (*snmpInit)() = NULL;
extern int diagLogging;
+static const NamespaceString startupLogCollectionName("local.startup_log");
+
#ifdef _WIN32
ntservice::NtServiceDefaultStrings defaultServiceStrings = {
L"MongoDB", L"MongoDB", L"MongoDB Server"};
@@ -232,18 +238,17 @@ static void logStartup(OperationContext* txn) {
ScopedTransaction transaction(txn, MODE_X);
Lock::GlobalWrite lk(txn->lockState());
- AutoGetOrCreateDb autoDb(txn, "local", mongo::MODE_X);
+ AutoGetOrCreateDb autoDb(txn, startupLogCollectionName.db(), mongo::MODE_X);
Database* db = autoDb.getDb();
- const std::string ns = "local.startup_log";
- Collection* collection = db->getCollection(ns);
+ Collection* collection = db->getCollection(startupLogCollectionName);
WriteUnitOfWork wunit(txn);
if (!collection) {
BSONObj options = BSON("capped" << true << "size" << 10 * 1024 * 1024);
bool shouldReplicateWrites = txn->writesAreReplicated();
txn->setReplicatedWrites(false);
ON_BLOCK_EXIT(&OperationContext::setReplicatedWrites, txn, shouldReplicateWrites);
- uassertStatusOK(userCreateNS(txn, db, ns, options));
- collection = db->getCollection(ns);
+ uassertStatusOK(userCreateNS(txn, db, startupLogCollectionName.ns(), options));
+ collection = db->getCollection(startupLogCollectionName);
}
invariant(collection);
uassertStatusOK(collection->insertDocument(txn, o, false));
@@ -299,6 +304,76 @@ static unsigned long long checkIfReplMissingFromCommandLine(OperationContext* tx
return 0;
}
+/**
+ * Due to SERVER-23274, versions 3.2.0 through 3.2.4 of MongoDB incorrectly mark the final output
+ * collections of aggregations with $out stages as temporary on most replica set secondaries. Rather
+ * than risk deleting collections that the user did not intend to be temporary when newer nodes
+ * start up or get promoted to be replica set primaries, newer nodes clear the temp flags left by
+ * these versions.
+ */
+static bool isSubjectToSERVER23299(OperationContext* txn) {
+ dbHolder().openDb(txn, startupLogCollectionName.db());
+ AutoGetCollectionForRead autoColl(txn, startupLogCollectionName);
+ // No startup log or an empty one means either that the user was not running an affected
+ // version, or that they manually deleted the startup collection since they last started an
+ // affected version.
+ LOG(1) << "Checking node for SERVER-23299 eligibility";
+ if (!autoColl.getCollection()) {
+ LOG(1) << "Didn't find " << startupLogCollectionName;
+ return false;
+ }
+ LOG(1) << "Checking node for SERVER-23299 applicability - reading startup log";
+ BSONObj lastStartupLogDoc;
+ if (!Helpers::getLast(txn, startupLogCollectionName.ns().c_str(), lastStartupLogDoc)) {
+ return false;
+ }
+ std::vector<int> versionComponents;
+ try {
+ for (auto elem : lastStartupLogDoc["buildinfo"]["versionArray"].Obj()) {
+ versionComponents.push_back(elem.Int());
+ }
+ uassert(40050,
+ str::stream() << "Expected three elements in buildinfo.versionArray; found "
+ << versionComponents.size(),
+ versionComponents.size() >= 3);
+ } catch (const DBException& ex) {
+ log() << "Last entry of " << startupLogCollectionName
+ << " has no well-formed buildinfo.versionArray field; ignoring " << causedBy(ex);
+ return false;
+ }
+ LOG(1)
+ << "Checking node for SERVER-23299 applicability - checking version 3.2.x for x in [0, 4]";
+ if (versionComponents[0] != 3)
+ return false;
+ if (versionComponents[1] != 2)
+ return false;
+ if (versionComponents[2] > 4)
+ return false;
+ LOG(1) << "Node eligible for SERVER-23299";
+ return true;
+}
+
+static void handleSERVER23299ForDb(OperationContext* txn, Database* db) {
+ log() << "Scanning " << db->name() << " db for SERVER-23299 eligibility";
+ const auto dbEntry = db->getDatabaseCatalogEntry();
+ list<string> collNames;
+ dbEntry->getCollectionNamespaces(&collNames);
+ for (const auto& collName : collNames) {
+ const auto collEntry = dbEntry->getCollectionCatalogEntry(collName);
+ const auto collOptions = collEntry->getCollectionOptions(txn);
+ if (!collOptions.temp)
+ continue;
+ log() << "Marking collection " << collName << " as permanent per SERVER-23299";
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
+ WriteUnitOfWork wuow(txn);
+ collEntry->clearTempFlag(txn);
+ wuow.commit();
+ }
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "repair SERVER-23299", collEntry->ns().ns());
+ }
+ log() << "Done scanning " << db->name() << " for SERVER-23299 eligibility";
+}
+
static void repairDatabasesAndCheckVersion(OperationContext* txn) {
LOG(1) << "enter repairDatabases (to check pdfile version #)" << endl;
@@ -307,7 +382,7 @@ static void repairDatabasesAndCheckVersion(OperationContext* txn) {
vector<string> dbNames;
- StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine();
+ StorageEngine* storageEngine = txn->getServiceContext()->getGlobalStorageEngine();
storageEngine->listDatabases(&dbNames);
// Repair all databases first, so that we do not try to open them if they are in bad shape
@@ -330,6 +405,8 @@ static void repairDatabasesAndCheckVersion(OperationContext* txn) {
!(checkIfReplMissingFromCommandLine(txn) || replSettings.usingReplSets() ||
replSettings.isSlave());
+ const bool shouldDoCleanupForSERVER23299 = isSubjectToSERVER23299(txn);
+
for (vector<string>::const_iterator i = dbNames.begin(); i != dbNames.end(); ++i) {
const string dbName = *i;
LOG(1) << " Recovering database: " << dbName << endl;
@@ -398,6 +475,10 @@ static void repairDatabasesAndCheckVersion(OperationContext* txn) {
checkForIdIndexes(txn, db);
}
+ if (shouldDoCleanupForSERVER23299) {
+ handleSERVER23299ForDb(txn, db);
+ }
+
if (shouldClearNonLocalTmpCollections || dbName == "local") {
db->clearTmpCollections(txn);
}
diff --git a/src/mongo/db/storage/kv/kv_collection_catalog_entry.cpp b/src/mongo/db/storage/kv/kv_collection_catalog_entry.cpp
index 2381a80fff6..38a9d2b3b09 100644
--- a/src/mongo/db/storage/kv/kv_collection_catalog_entry.cpp
+++ b/src/mongo/db/storage/kv/kv_collection_catalog_entry.cpp
@@ -163,6 +163,12 @@ void KVCollectionCatalogEntry::updateFlags(OperationContext* txn, int newValue)
_catalog->putMetaData(txn, ns().toString(), md);
}
+void KVCollectionCatalogEntry::clearTempFlag(OperationContext* txn) {
+ MetaData md = _getMetaData(txn);
+ md.options.temp = false;
+ _catalog->putMetaData(txn, ns().ns(), md);
+}
+
void KVCollectionCatalogEntry::updateValidator(OperationContext* txn,
const BSONObj& validator,
StringData validationLevel,
diff --git a/src/mongo/db/storage/kv/kv_collection_catalog_entry.h b/src/mongo/db/storage/kv/kv_collection_catalog_entry.h
index 11cc4ecafc6..3a3704e82d5 100644
--- a/src/mongo/db/storage/kv/kv_collection_catalog_entry.h
+++ b/src/mongo/db/storage/kv/kv_collection_catalog_entry.h
@@ -68,6 +68,8 @@ public:
void updateFlags(OperationContext* txn, int newValue) final;
+ void clearTempFlag(OperationContext* txn) final;
+
void updateValidator(OperationContext* txn,
const BSONObj& validator,
StringData validationLevel,
diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp
index 736c3c11acc..278474cabb0 100644
--- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp
+++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.cpp
@@ -372,6 +372,10 @@ void NamespaceDetailsCollectionCatalogEntry::updateFlags(OperationContext* txn,
_updateSystemNamespaces(txn, BSON("$set" << BSON("options.flags" << newValue)));
}
+void NamespaceDetailsCollectionCatalogEntry::clearTempFlag(OperationContext* txn) {
+ _updateSystemNamespaces(txn, BSON("$set" << BSON("options.temp" << false)));
+}
+
void NamespaceDetailsCollectionCatalogEntry::updateValidator(OperationContext* txn,
const BSONObj& validator,
StringData validationLevel,
diff --git a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h
index 4bdebf31d5e..89760adf99a 100644
--- a/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h
+++ b/src/mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h
@@ -93,6 +93,8 @@ public:
void updateFlags(OperationContext* txn, int newValue) final;
+ void clearTempFlag(OperationContext* txn) final;
+
void updateValidator(OperationContext* txn,
const BSONObj& validator,
StringData validationLevel,