summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/repl/SConscript1
-rw-r--r--src/mongo/db/repl/primary_only_service.cpp12
-rw-r--r--src/mongo/db/repl/primary_only_service.h11
-rw-r--r--src/mongo/db/repl/primary_only_service_test.cpp34
-rw-r--r--src/mongo/db/repl/replication_info.cpp24
5 files changed, 74 insertions, 8 deletions
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index eeddbed7948..0ef88b0a410 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -1232,6 +1232,7 @@ env.Library(
'$BUILD_DIR/mongo/db/repl/speculative_authenticate',
'$BUILD_DIR/mongo/db/stats/counters',
'$BUILD_DIR/mongo/transport/message_compressor',
+ 'primary_only_service',
'replication_auth',
'split_horizon',
],
diff --git a/src/mongo/db/repl/primary_only_service.cpp b/src/mongo/db/repl/primary_only_service.cpp
index acf79190d1b..ab7f25ec861 100644
--- a/src/mongo/db/repl/primary_only_service.cpp
+++ b/src/mongo/db/repl/primary_only_service.cpp
@@ -227,9 +227,21 @@ void PrimaryOnlyServiceRegistry::onStepDown() {
}
}
+void PrimaryOnlyServiceRegistry::reportServiceInfo(BSONObjBuilder* result) {
+ BSONObjBuilder subBuilder(result->subobjStart("primaryOnlyServices"));
+ for (auto& service : _servicesByName) {
+ subBuilder.appendNumber(service.first, service.second->getNumberOfInstances());
+ }
+}
+
PrimaryOnlyService::PrimaryOnlyService(ServiceContext* serviceContext)
: _serviceContext(serviceContext) {}
+size_t PrimaryOnlyService::getNumberOfInstances() {
+ stdx::lock_guard lk(_mutex);
+ return _instances.size();
+}
+
bool PrimaryOnlyService::isRunning() const {
stdx::lock_guard lk(_mutex);
return _state == State::kRunning;
diff --git a/src/mongo/db/repl/primary_only_service.h b/src/mongo/db/repl/primary_only_service.h
index 0d57cf96d9b..664ecd9fa11 100644
--- a/src/mongo/db/repl/primary_only_service.h
+++ b/src/mongo/db/repl/primary_only_service.h
@@ -217,6 +217,11 @@ public:
*/
bool isRunning() const;
+ /**
+ * Returns the number of currently running Instances of this service.
+ */
+ size_t getNumberOfInstances();
+
protected:
/**
* Constructs a new Instance object with the given initial state.
@@ -328,6 +333,12 @@ public:
*/
PrimaryOnlyService* lookupServiceByNamespace(const NamespaceString& ns);
+ /**
+ * Adds a 'primaryOnlyServices' sub-obj to the 'result' BSONObjBuilder containing a count of the
+ * number of active instances for each registered service.
+ */
+ void reportServiceInfo(BSONObjBuilder* result);
+
void onStartup(OperationContext*) final;
void onShutdown() final;
void onStepUpBegin(OperationContext*, long long term) final {}
diff --git a/src/mongo/db/repl/primary_only_service_test.cpp b/src/mongo/db/repl/primary_only_service_test.cpp
index d89005e8b1d..d7c76b6b7cb 100644
--- a/src/mongo/db/repl/primary_only_service_test.cpp
+++ b/src/mongo/db/repl/primary_only_service_test.cpp
@@ -367,6 +367,40 @@ TEST_F(PrimaryOnlyServiceTest, DoubleCreateInstance) {
TestServiceHangDuringInitialization.setMode(FailPoint::off);
}
+TEST_F(PrimaryOnlyServiceTest, ReportServiceInfo) {
+ {
+ BSONObjBuilder resultBuilder;
+ _registry->reportServiceInfo(&resultBuilder);
+
+ ASSERT_BSONOBJ_EQ(BSON("primaryOnlyServices" << BSON("TestService" << 0)),
+ resultBuilder.obj());
+ }
+
+ // Make sure the instance doesn't complete.
+ TestServiceHangDuringInitialization.setMode(FailPoint::alwaysOn);
+ auto instance = TestService::Instance::getOrCreate(_service, BSON("_id" << 0 << "state" << 0));
+
+ {
+ BSONObjBuilder resultBuilder;
+ _registry->reportServiceInfo(&resultBuilder);
+
+ ASSERT_BSONOBJ_EQ(BSON("primaryOnlyServices" << BSON("TestService" << 1)),
+ resultBuilder.obj());
+ }
+
+ auto instance2 = TestService::Instance::getOrCreate(_service, BSON("_id" << 1 << "state" << 0));
+
+ {
+ BSONObjBuilder resultBuilder;
+ _registry->reportServiceInfo(&resultBuilder);
+
+ ASSERT_BSONOBJ_EQ(BSON("primaryOnlyServices" << BSON("TestService" << 2)),
+ resultBuilder.obj());
+ }
+
+ TestServiceHangDuringInitialization.setMode(FailPoint::off);
+}
+
TEST_F(PrimaryOnlyServiceTest, CreateWhenNotPrimary) {
_registry->onStepDown();
diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp
index ec551d390ea..188de5e8d16 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -50,6 +50,7 @@
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/is_master_response.h"
+#include "mongo/db/repl/primary_only_service.h"
#include "mongo/db/repl/replication_auth.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/repl/replication_process.h"
@@ -86,12 +87,17 @@ constexpr auto kHelloString = "hello"_sd;
constexpr auto kCamelCaseIsMasterString = "isMaster"_sd;
constexpr auto kLowerCaseIsMasterString = "ismaster"_sd;
+void appendPrimaryOnlyServiceInfo(ServiceContext* serviceContext, BSONObjBuilder* result) {
+ auto registry = PrimaryOnlyServiceRegistry::get(serviceContext);
+ registry->reportServiceInfo(result);
+}
+
/**
* Appends replication-related fields to the isMaster response. Returns the topology version that
* was included in the response.
*/
TopologyVersion appendReplicationInfo(OperationContext* opCtx,
- BSONObjBuilder& result,
+ BSONObjBuilder* result,
bool appendReplicationProcess,
bool useLegacyResponseFields,
boost::optional<TopologyVersion> clientTopologyVersion,
@@ -108,9 +114,9 @@ TopologyVersion appendReplicationInfo(OperationContext* opCtx,
}
auto isMasterResponse =
replCoord->awaitIsMasterResponse(opCtx, horizonParams, clientTopologyVersion, deadline);
- result.appendElements(isMasterResponse->toBSON(useLegacyResponseFields));
+ result->appendElements(isMasterResponse->toBSON(useLegacyResponseFields));
if (appendReplicationProcess) {
- replCoord->appendSlaveInfoData(&result);
+ replCoord->appendSlaveInfoData(result);
}
invariant(isMasterResponse->getTopologyVersion());
return isMasterResponse->getTopologyVersion().get();
@@ -142,10 +148,10 @@ TopologyVersion appendReplicationInfo(OperationContext* opCtx,
opCtx->sleepFor(Milliseconds(*maxAwaitTimeMS));
}
- result.appendBool((useLegacyResponseFields ? "ismaster" : "isWritablePrimary"),
- ReplicationCoordinator::get(opCtx)->isMasterForReportingPurposes());
+ result->appendBool((useLegacyResponseFields ? "ismaster" : "isWritablePrimary"),
+ ReplicationCoordinator::get(opCtx)->isMasterForReportingPurposes());
- BSONObjBuilder topologyVersionBuilder(result.subobjStart("topologyVersion"));
+ BSONObjBuilder topologyVersionBuilder(result->subobjStart("topologyVersion"));
currentTopologyVersion.serialize(&topologyVersionBuilder);
return currentTopologyVersion;
@@ -171,12 +177,14 @@ public:
// TODO SERVER-50219: Change useLegacyResponseFields to false once the serverStatus changes
// to remove master-slave terminology are merged.
appendReplicationInfo(opCtx,
- result,
+ &result,
appendReplicationProcess,
true /* useLegacyResponseFields */,
boost::none /* clientTopologyVersion */,
boost::none /* maxAwaitTimeMS */);
+ appendPrimaryOnlyServiceInfo(opCtx->getServiceContext(), &result);
+
auto rbid = ReplicationProcess::get(opCtx)->getRollbackID();
if (ReplicationProcess::kUninitializedRollbackId != rbid) {
result.append("rbid", rbid);
@@ -426,7 +434,7 @@ public:
auto result = replyBuilder->getBodyBuilder();
auto currentTopologyVersion = appendReplicationInfo(
- opCtx, result, 0, useLegacyResponseFields, clientTopologyVersion, maxAwaitTimeMS);
+ opCtx, &result, 0, useLegacyResponseFields, clientTopologyVersion, maxAwaitTimeMS);
if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) {
const int configServerModeNumber = 2;