forked from mongodb/genny
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding in PoolFactory class with MongoURI munging (mongodb#61)
* Added in a Uri class that pops a true uri in and out of mongoc * Added in the server clang-format * Made generate-uuid.sh script
- Loading branch information
Showing
9 changed files
with
426 additions
and
19 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#/bin/bash | ||
|
||
UUID=$(uuidgen | sed s/-/_/g | tr a-z A-Z) | ||
echo "HEADER_${UUID}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
#ifndef HEADER_3BB17688_900D_4AFB_B736_C9EC8DA9E33B | ||
#define HEADER_3BB17688_900D_4AFB_B736_C9EC8DA9E33B | ||
|
||
#include <functional> | ||
#include <map> | ||
#include <memory> | ||
#include <set> | ||
#include <string> | ||
#include <string_view> | ||
|
||
#include <mongocxx/pool.hpp> | ||
|
||
namespace genny { | ||
|
||
/** | ||
* A pool factory takes in a MongoURI, modifies its components, and makes a pool from it | ||
* | ||
* This class allows for programically modifying all non-host components of the MongoURI. | ||
* Any query parameter can be set via `setStringOption()`, `setIntOption()`, or `setFlag()`. | ||
* It also allows for setting the protocol, username, password, and database via the options | ||
* "Protocol", "Username", "Password", and "Database" in the same manner as query parameters would | ||
* be set. Lastly, it allows for programatically setting up the ssl options for the connection pool | ||
* via `configureSsl()`. | ||
*/ | ||
class PoolFactory { | ||
public: | ||
PoolFactory(std::string_view uri); | ||
~PoolFactory(); | ||
|
||
std::string makeUri() const; | ||
std::unique_ptr<mongocxx::pool> makePool() const; | ||
|
||
/** | ||
* Options of note: | ||
* minPoolSize | ||
* maxPoolSize | ||
* connectTimeoutMS | ||
* socketTimeoutMS | ||
*/ | ||
void setStringOption(const std::string & option, std::string value); | ||
void setIntOption(const std::string & option, int32_t value); | ||
void setFlag(const std::string & option, bool value = true); | ||
|
||
void configureSsl(mongocxx::options::ssl options, bool enableSsl = true); | ||
|
||
private: | ||
struct Config; | ||
std::unique_ptr<Config> _config; | ||
}; | ||
|
||
} // namespace genny | ||
|
||
#endif // HEADER_3BB17688_900D_4AFB_B736_C9EC8DA9E33B |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
#include <gennylib/PoolFactory.hpp> | ||
|
||
#include <iostream> | ||
#include <map> | ||
#include <regex> | ||
#include <set> | ||
#include <sstream> | ||
|
||
#include <boost/log/trivial.hpp> | ||
#include <mongocxx/uri.hpp> | ||
|
||
#include <gennylib/InvalidConfigurationException.hpp> | ||
|
||
namespace genny { | ||
|
||
struct PoolFactory::Config { | ||
Config(std::string_view uri) { | ||
const auto protocolRegex = std::regex("^(mongodb://|mongodb+srv://)?(([^:@]*):([^@]*)@)?"); | ||
const auto hostRegex = std::regex("^,?([^:,/]+(:[0-9]+)?)"); | ||
const auto dbRegex = std::regex("^/([^?]*)\\??"); | ||
const auto queryRegex = std::regex("^&?([^=&]*)=([^&]*)"); | ||
|
||
std::cmatch matches; | ||
auto i = 0; | ||
|
||
// Extract the protocol, and optionally the username and the password | ||
std::regex_search(uri.substr(i).data(), matches, protocolRegex); | ||
if (matches.length(1)) { | ||
accessOptions["Protocol"] = matches[1]; | ||
} else { | ||
accessOptions["Protocol"] = "mongodb://"; | ||
} | ||
if (matches.length(3)) | ||
accessOptions["Username"] = matches[3]; | ||
if (matches.length(4)) | ||
accessOptions["Password"] = matches[4]; | ||
i += matches.length(); | ||
|
||
// Extract each host specified in the uri | ||
while (std::regex_search(uri.substr(i).data(), matches, hostRegex)) { | ||
hosts.insert(matches[1]); | ||
i += matches.length(); | ||
} | ||
|
||
// Extract the db name and optionally the query string prefix | ||
std::regex_search(uri.substr(i).data(), matches, dbRegex); | ||
accessOptions["Database"] = matches[1]; | ||
i += matches.length(); | ||
|
||
// Extract each query parameter | ||
// Note that the official syntax of query strings is poorly defined, keys without values may | ||
// be valid but not supported here. | ||
while (std::regex_search(uri.substr(i).data(), matches, queryRegex)) { | ||
auto key = matches[1]; | ||
auto value = matches[2]; | ||
queryOptions[key] = value; | ||
i += matches.length(); | ||
} | ||
} | ||
|
||
auto makeUri() const { | ||
std::ostringstream ss; | ||
size_t i; | ||
|
||
ss << accessOptions.at("Protocol"); | ||
if (!accessOptions.at("Username").empty()) { | ||
ss << accessOptions.at("Username") << ':' << accessOptions.at("Password") << '@'; | ||
} | ||
|
||
i = 0; | ||
for (auto& host : hosts) { | ||
if (i++ > 0) { | ||
ss << ','; | ||
} | ||
ss << host; | ||
} | ||
|
||
auto dbName = accessOptions.at("Database"); | ||
if (!dbName.empty() || !queryOptions.empty()) { | ||
ss << '/' << accessOptions.at("Database"); | ||
} | ||
|
||
if (!queryOptions.empty()) { | ||
ss << '?'; | ||
} | ||
|
||
i = 0; | ||
for (auto && [ key, value ] : queryOptions) { | ||
if (i++ > 0) { | ||
ss << '&'; | ||
} | ||
ss << key << '=' << value; | ||
} | ||
|
||
return ss.str(); | ||
} | ||
|
||
std::set<std::string> hosts; | ||
std::map<std::string, std::string> queryOptions; | ||
std::map<std::string, std::string> accessOptions = { | ||
{"Protocol", ""}, {"Username", ""}, {"Password", ""}, {"Database", ""}, | ||
}; | ||
mongocxx::options::pool poolOptions; | ||
}; | ||
|
||
PoolFactory::PoolFactory(std::string_view rawUri) : _config(std::make_unique<Config>(rawUri)) {} | ||
PoolFactory::~PoolFactory() {} | ||
|
||
std::string PoolFactory::makeUri() const { | ||
return _config->makeUri(); | ||
} | ||
|
||
std::unique_ptr<mongocxx::pool> PoolFactory::makePool() const { | ||
auto uriStr = makeUri(); | ||
BOOST_LOG_TRIVIAL(info) << "Constructing pool with MongoURI '" << uriStr << "'"; | ||
|
||
auto uri = mongocxx::uri{uriStr}; | ||
return std::make_unique<mongocxx::pool>(uri, _config->poolOptions); | ||
} | ||
|
||
void PoolFactory::setStringOption(const std::string& option, std::string value) { | ||
// If the value is in the accessOptions set, set it | ||
auto it = _config->accessOptions.find(option); | ||
if (it != _config->accessOptions.end()) { | ||
it->second = value; | ||
return; | ||
} | ||
|
||
// Treat the value as a normal query parameter | ||
_config->queryOptions[option] = value; | ||
} | ||
|
||
void PoolFactory::setIntOption(const std::string& option, int32_t value) { | ||
auto valueStr = std::to_string(value); | ||
setStringOption(option, valueStr); | ||
} | ||
|
||
void PoolFactory::setFlag(const std::string& option, bool value) { | ||
auto valueStr = value ? "true" : "false"; | ||
setStringOption(option, valueStr); | ||
} | ||
|
||
void PoolFactory::configureSsl(mongocxx::options::ssl options, bool enableSsl) { | ||
setFlag("ssl", enableSsl); | ||
|
||
auto clientOpts = _config->poolOptions.client_opts(); | ||
_config->poolOptions = clientOpts.ssl_opts(options); | ||
} | ||
|
||
} // namespace genny |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.