diff options
author | Andy Schwerin <schwerin@10gen.com> | 2012-09-13 11:54:44 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@10gen.com> | 2012-09-25 15:43:02 -0400 |
commit | 1c9b2a7d236cce265db1b29a708959fe87ba56ca (patch) | |
tree | 6e70af1c59131ce2f9c3d6b8e0c0e1f9045652c4 | |
parent | 6825307dd6534086ffbf8442eb9b5ac3cd9c13d3 (diff) | |
download | mongo-1c9b2a7d236cce265db1b29a708959fe87ba56ca.tar.gz |
SERVER-5112 Initializer type and test.
-rw-r--r-- | src/mongo/base/SConscript | 4 | ||||
-rw-r--r-- | src/mongo/base/error_codes.h | 3 | ||||
-rw-r--r-- | src/mongo/base/initializer.cpp | 47 | ||||
-rw-r--r-- | src/mongo/base/initializer.h | 71 | ||||
-rw-r--r-- | src/mongo/base/initializer_context.cpp | 25 | ||||
-rw-r--r-- | src/mongo/base/initializer_context.h | 53 | ||||
-rw-r--r-- | src/mongo/base/initializer_test.cpp | 165 |
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 |