summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@10gen.com>2012-09-13 11:54:44 -0400
committerAndy Schwerin <schwerin@10gen.com>2012-09-25 15:43:02 -0400
commit1c9b2a7d236cce265db1b29a708959fe87ba56ca (patch)
tree6e70af1c59131ce2f9c3d6b8e0c0e1f9045652c4
parent6825307dd6534086ffbf8442eb9b5ac3cd9c13d3 (diff)
downloadmongo-1c9b2a7d236cce265db1b29a708959fe87ba56ca.tar.gz
SERVER-5112 Initializer type and test.
-rw-r--r--src/mongo/base/SConscript4
-rw-r--r--src/mongo/base/error_codes.h3
-rw-r--r--src/mongo/base/initializer.cpp47
-rw-r--r--src/mongo/base/initializer.h71
-rw-r--r--src/mongo/base/initializer_context.cpp25
-rw-r--r--src/mongo/base/initializer_context.h53
-rw-r--r--src/mongo/base/initializer_test.cpp165
7 files changed, 368 insertions, 0 deletions
diff --git a/src/mongo/base/SConscript b/src/mongo/base/SConscript
index 6bc1aa8a7cb..0c7d29abe9b 100644
--- a/src/mongo/base/SConscript
+++ b/src/mongo/base/SConscript
@@ -3,6 +3,8 @@
Import("env")
env.StaticLibrary('base', ['configuration_variable_manager.cpp',
+ 'initializer.cpp',
+ 'initializer_context.cpp',
'initializer_dependency_graph.cpp',
'make_string_vector.cpp',
'parse_number.cpp',
@@ -24,3 +26,5 @@ env.CppUnitTest('configuration_variable_manager_test',
env.CppUnitTest('parse_number_test', ['parse_number_test.cpp'], LIBDEPS=['base'])
+env.CppUnitTest('initializer_test', ['initializer_test.cpp'], LIBDEPS=['base'])
+
diff --git a/src/mongo/base/error_codes.h b/src/mongo/base/error_codes.h
index 0cc9dfafdf2..3c53e8b8080 100644
--- a/src/mongo/base/error_codes.h
+++ b/src/mongo/base/error_codes.h
@@ -49,6 +49,7 @@ namespace mongo {
GraphContainsCycle = 5,
HostUnreachable = 6,
HostNotFound = 7,
+ UnknownError = 8,
FailedToParse = 9,
MaxError
};
@@ -71,6 +72,8 @@ namespace mongo {
return "DuplicateKey";
case GraphContainsCycle:
return "GraphContainsCycle";
+ case UnknownError:
+ return "UnknownError";
case FailedToParse:
return "FailedToParse";
default:
diff --git a/src/mongo/base/initializer.cpp b/src/mongo/base/initializer.cpp
new file mode 100644
index 00000000000..f1921ba5637
--- /dev/null
+++ b/src/mongo/base/initializer.cpp
@@ -0,0 +1,47 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/base/initializer.h"
+
+namespace mongo {
+
+ Initializer::Initializer() {}
+ Initializer::~Initializer() {}
+
+ Status Initializer::execute(const InitializerContext::ArgumentVector& args,
+ const InitializerContext::EnvironmentMap& env) const {
+
+ std::vector<std::string> sortedNodes;
+ Status status = _graph.topSort(&sortedNodes);
+ if (Status::OK() != status)
+ return status;
+
+ InitializerContext context(args, env, &_configVariables);
+
+ for (size_t i = 0; i < sortedNodes.size(); ++i) {
+ InitializerFunction fn = _graph.getInitializerFunction(sortedNodes[i]);
+ if (!fn) {
+ return Status(ErrorCodes::InternalError,
+ "topSort returned a node that has no associated function: \"" +
+ sortedNodes[i] + '"');
+ }
+ status = fn(&context);
+ if (Status::OK() != status)
+ return status;
+ }
+ return Status::OK();
+ }
+
+} // namespace mongo
diff --git a/src/mongo/base/initializer.h b/src/mongo/base/initializer.h
new file mode 100644
index 00000000000..7d03cd6e40c
--- /dev/null
+++ b/src/mongo/base/initializer.h
@@ -0,0 +1,71 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "mongo/base/configuration_variable_manager.h"
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/initializer_context.h"
+#include "mongo/base/initializer_dependency_graph.h"
+#include "mongo/base/status.h"
+
+namespace mongo {
+
+ /**
+ * Class representing an initialization process.
+ *
+ * Such a process is described by a directed acyclic graph of initialization operations, the
+ * InitializerDependencyGraph, and a collection of mutable global state, the
+ * ConfigurationVariableManager. One constructs an initialization process by adding nodes and
+ * edges to the graph, and variable mappings in the variable manager. Then, one executes the
+ * process, causing each initialization operation to execute in an order that respects the
+ * programmer-established prerequistes.
+ */
+ class Initializer {
+ MONGO_DISALLOW_COPYING(Initializer);
+ public:
+ Initializer();
+ ~Initializer();
+
+ /**
+ * Get the initializer dependency graph, presumably for the purpose of adding more nodes.
+ */
+ InitializerDependencyGraph& getInitializerDependencyGraph() { return _graph; }
+
+ /**
+ * Get the configuration variable manager, for the purpose of describing more configurable
+ * variables.
+ */
+ ConfigurationVariableManager& getConfigurationVariableManager() { return _configVariables; }
+
+ /**
+ * Execute the initializer process, using the given argv and environment data as input.
+ *
+ * Returns Status::OK on success. All other returns constitute initialization failures,
+ * and the thing being initialized should be considered dead in the water.
+ */
+ Status execute(const InitializerContext::ArgumentVector& args,
+ const InitializerContext::EnvironmentMap& env) const;
+
+ private:
+
+ InitializerDependencyGraph _graph;
+ ConfigurationVariableManager _configVariables;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/base/initializer_context.cpp b/src/mongo/base/initializer_context.cpp
new file mode 100644
index 00000000000..9c2e54caf3f
--- /dev/null
+++ b/src/mongo/base/initializer_context.cpp
@@ -0,0 +1,25 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/base/initializer_context.h"
+
+namespace mongo {
+
+ InitializerContext::InitializerContext(const ArgumentVector& args,
+ const EnvironmentMap& env,
+ const ConfigurationVariableManager* configVariables)
+ : _args(args), _env(env), _configVariables(configVariables) {}
+
+} // namespace mongo
diff --git a/src/mongo/base/initializer_context.h b/src/mongo/base/initializer_context.h
new file mode 100644
index 00000000000..915e18f600e
--- /dev/null
+++ b/src/mongo/base/initializer_context.h
@@ -0,0 +1,53 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "mongo/base/configuration_variable_manager.h"
+#include "mongo/base/disallow_copying.h"
+
+namespace mongo {
+
+ /**
+ * Context of an initialization process. Passed as a parameter to initialization functions.
+ *
+ * See mongo/base/initializer.h and mongo/base/initializer_dependency_graph.h for more details.
+ */
+ class InitializerContext {
+ MONGO_DISALLOW_COPYING(InitializerContext);
+
+ public:
+ typedef std::vector<std::string> ArgumentVector;
+ typedef std::map<std::string, std::string> EnvironmentMap;
+
+ InitializerContext(const ArgumentVector& args,
+ const EnvironmentMap& env,
+ const ConfigurationVariableManager* configVariables);
+
+ const ArgumentVector& args() const { return _args; }
+ const EnvironmentMap& env() const { return _env; }
+ const ConfigurationVariableManager* configurationVariables() { return _configVariables; }
+
+ private:
+ ArgumentVector _args;
+ EnvironmentMap _env;
+ const ConfigurationVariableManager* _configVariables;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/base/initializer_test.cpp b/src/mongo/base/initializer_test.cpp
new file mode 100644
index 00000000000..88824f15ba8
--- /dev/null
+++ b/src/mongo/base/initializer_test.cpp
@@ -0,0 +1,165 @@
+/* Copyright 2012 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Unit tests of the Initializer type.
+ */
+
+#include "mongo/base/initializer.h"
+#include "mongo/base/initializer_dependency_graph.h"
+#include "mongo/base/make_string_vector.h"
+#include "mongo/unittest/unittest.h"
+
+/*
+ * Unless otherwise specified, all tests herein use the following
+ * dependency graph.
+ *
+ * 0 <- 3 <- 7
+ * ^ / ^ ^
+ * \ v \ \
+ * 2 5 <- 8
+ * / ^ / /
+ * v \ v v
+ * 1 <- 4 <- 6
+ *
+ */
+
+#define ADD_INITIALIZER(GRAPH, NAME, FN, PREREQS, DEPS) \
+ (GRAPH).addInitializer( \
+ (NAME), \
+ (FN), \
+ MONGO_MAKE_STRING_VECTOR PREREQS, \
+ MONGO_MAKE_STRING_VECTOR DEPS)
+
+#define ASSERT_OK(EXPR) ASSERT_EQUALS(Status::OK(), EXPR)
+
+#define ASSERT_ADD_INITIALIZER(GRAPH, NAME, FN, PREREQS, DEPS) \
+ ASSERT_EQUALS(Status::OK(), ADD_INITIALIZER(GRAPH, NAME, FN, PREREQS, DEPS))
+
+
+#define CONSTRUCT_DEPENDENCY_GRAPH(GRAPH, FN0, FN1, FN2, FN3, FN4, FN5, FN6, FN7, FN8) \
+ do { \
+ InitializerDependencyGraph& _graph_ = (GRAPH); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n0", FN0, (), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n1", FN1, (), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n2", FN2, ("n0", "n1"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n3", FN3, ("n0", "n2"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n4", FN4, ("n2", "n1"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n5", FN5, ("n3", "n4"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n6", FN6, ("n4"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n7", FN7, ("n3"), ()); \
+ ASSERT_ADD_INITIALIZER(_graph_, "n8", FN8, ("n5", "n6", "n7"), ()); \
+ } while (false)
+
+namespace mongo {
+namespace {
+
+ int globalCounts[9];
+
+ Status doNothing(InitializerContext*) { return Status::OK(); }
+
+ Status set0(InitializerContext*) {
+ globalCounts[0] = 1;
+ return Status::OK();
+ }
+
+ Status set1(InitializerContext*) {
+ globalCounts[1] = 1;
+ return Status::OK();
+ }
+
+ Status set2(InitializerContext*) {
+ if (!globalCounts[0] || !globalCounts[1])
+ return Status(ErrorCodes::UnknownError, "one of 0 or 1 not already set");
+ globalCounts[2] = 1;
+ return Status::OK();
+ }
+
+ Status set3(InitializerContext*) {
+ if (!globalCounts[0] || !globalCounts[2])
+ return Status(ErrorCodes::UnknownError, "one of 0 or 2 not already set");
+ globalCounts[3] = 1;
+ return Status::OK();
+ }
+
+ Status set4(InitializerContext*) {
+ if (!globalCounts[1] || !globalCounts[2])
+ return Status(ErrorCodes::UnknownError, "one of 1 or 2 not already set");
+ globalCounts[4] = 1;
+ return Status::OK();
+ }
+
+ Status set5(InitializerContext*) {
+ if (!globalCounts[3] || !globalCounts[4])
+ return Status(ErrorCodes::UnknownError, "one of 3 or 4 not already set");
+ globalCounts[5] = 1;
+ return Status::OK();
+ }
+
+ Status set6(InitializerContext*) {
+ if (!globalCounts[4])
+ return Status(ErrorCodes::UnknownError, "4 not already set");
+ globalCounts[6] = 1;
+ return Status::OK();
+ }
+
+ Status set7(InitializerContext*) {
+ if (!globalCounts[3])
+ return Status(ErrorCodes::UnknownError, "3 not already set");
+ globalCounts[7] = 1;
+ return Status::OK();
+ }
+
+ Status set8(InitializerContext*) {
+ if (!globalCounts[5] || !globalCounts[6] || !globalCounts[7])
+ return Status(ErrorCodes::UnknownError, "one of 5, 6, 7 not already set");
+ globalCounts[8] = 1;
+ return Status::OK();
+ }
+
+ void clearCounts() {
+ for (size_t i = 0; i < 9; ++i)
+ globalCounts[i] = 0;
+ }
+
+ TEST(InitializerTest, SuccessfulInitialization) {
+ Initializer initializer;
+ CONSTRUCT_DEPENDENCY_GRAPH(initializer.getInitializerDependencyGraph(),
+ set0, set1, set2, set3, set4, set5, set6, set7, set8);
+ clearCounts();
+ ASSERT_OK(initializer.execute(InitializerContext::ArgumentVector(),
+ InitializerContext::EnvironmentMap()));
+ for (int i = 0; i < 9; ++i)
+ ASSERT_EQUALS(1, globalCounts[i]);
+ }
+
+ TEST(InitializerTest, Step5Misimplemented) {
+ Initializer initializer;
+ CONSTRUCT_DEPENDENCY_GRAPH(initializer.getInitializerDependencyGraph(),
+ set0, set1, set2, set3, set4, doNothing, set6, set7, set8);
+ clearCounts();
+ ASSERT_EQUALS(ErrorCodes::UnknownError,
+ initializer.execute(InitializerContext::ArgumentVector(),
+ InitializerContext::EnvironmentMap()));
+ ASSERT_EQUALS(1, globalCounts[0]);
+ ASSERT_EQUALS(1, globalCounts[1]);
+ ASSERT_EQUALS(1, globalCounts[2]);
+ ASSERT_EQUALS(1, globalCounts[3]);
+ ASSERT_EQUALS(1, globalCounts[4]);
+ ASSERT_EQUALS(0, globalCounts[8]);
+ }
+
+} // namespace
+} // namespace mongo