Sleds/K2Daemon/MongoDB.cpp

147 lines
4.6 KiB
C++

/*
Copyright (c) 2013, 2014 IOnU Security Inc. All rights reserved. Copyright (c) 2015, 2016 Sequence Logic, Inc.
Created August 2013 by Kendrick Webster
K2Daemon/MongoDB.cpp - implementation for MongoDB.h
*/
#include "global.h"
#include "MongoDB.h"
#include <sstream>
// module static (local) data
namespace
{
mongoc_client_t *connection = NULL;
std::string mongoServer;
bool isConnected = false;
bool isDown = false; // true during transient failures (i.e. replica set primary goes down, new primary not yet elected)
CStopWatch stopwatch;
}
success_t MongoDB::Connect(const char* host, int port)
{
logprintf(Log::informational, "Connecting to MongoDB host %s port %d", host, port);
std::stringstream hostURI;
hostURI << "mongodb://" << host << ":" << port;
mongoServer = hostURI.str();
connection = mongoc_client_new(mongoServer.c_str());
if (connection == NULL)
{
isConnected = false;
logprintf(Log::error, "mongo_client (connect): \"mongodb://%s:%d\"", host, port);
return FAILURE;
}
isConnected = true;
isDown = false;
logprintf(Log::debug, "connected to MongoDB");
return SUCCESS;
}
success_t MongoDB::ConnectReplica(const std::string& replica_set_name, const std::string& hosts)
{
if (isConnected)
Disconnect();
logprintf(Log::informational, "Connecting to MongoDB replica set %s", replica_set_name.c_str());
std::stringstream repSetURI;
repSetURI << "mongodb://" << hosts << "/?replicaSet=" << replica_set_name;
mongoServer = repSetURI.str();
connection = mongoc_client_new(mongoServer.c_str());
if (connection == NULL)
{
logprintf(Log::error, "Cannot connect to replica set: \"mongodb://%s/?replicaSet=%s\"", hosts.c_str(), replica_set_name.c_str());
isConnected = false;
return FAILURE;
}
isConnected = true;
isDown = false;
logprintf(Log::debug, "connected to MongoDB");
return SUCCESS;
}
void MongoDB::Disconnect(void)
{
if (isConnected)
{
logprintf(Log::debug, "logging out of MongoDB");
mongoc_client_destroy(connection);
isConnected = false;
connection = NULL;
}
}
success_t MongoDB::Reconnect(void)
{
if (isConnected)
{
logprintf(Log::informational, "Re-connecting to MongoDB");
// It seems that the new C driver doesn't have a "reconnect" function!!!
Disconnect();
connection = mongoc_client_new(mongoServer.c_str());
if (connection == NULL)
{
isDown = true;
stopwatch.Reset();
logprintf(Log::error, "mongo_reconnect");
return FAILURE;
}
}
return FAILURE;
}
mongoc_client_t* MongoDB::GetConnection(void)
{
if (isDown || !isConnected)
{
return NULL;
}
return connection;
}
bool MongoDB::IsTemporaryOutage(void)
{
return isDown && isConnected;
}
const char* MongoDB::ErrorString(mongoc_error_code_t e)
{
static char buf[48];
switch (e)
{
//case MONGO_CONN_SUCCESS: return "Connection success!";
//case MONGO_CONN_NO_SOCKET: return "Could not create a socket.";
case MONGOC_ERROR_STREAM_CONNECT: return "An error occured while calling connect().";
case MONGOC_ERROR_STREAM_NAME_RESOLUTION: return "An error occured while calling getaddrinfo().";
//case MONGO_CONN_NOT_MASTER: return "Warning: connected to a non-master node (read-only).";
//case MONGO_CONN_BAD_SET_NAME: return "Given rs name doesn't match this replica set.";
//case MONGO_CONN_NO_PRIMARY: return "Can't find primary in replica set. Connection closed.";
//case MONGO_IO_ERROR: return "An error occurred while reading or writing on the socket.";
//case MONGOC_ERROR_STREAM_SOCKET: return "Other socket error.";
//case MONGO_READ_SIZE_ERROR: return "The response is not the expected length.";
//case MONGO_COMMAND_FAILED: return "The command returned with 'ok' value of 0.";
//case MONGO_WRITE_ERROR: return "Write with given write_concern returned an error.";
//case MONGO_NS_INVALID: return "The name for the ns (database or collection) is invalid.";
//case MONGO_BSON_INVALID: return "BSON not valid for the specified op.";
//case MONGO_BSON_NOT_FINISHED: return "BSON object has not been finished.";
//case MONGO_BSON_TOO_LARGE: return "BSON object exceeds max BSON size.";
//case MONGO_WRITE_CONCERN_INVALID: return "Supplied write concern object is invalid.";
default:
snprintf(buf, sizeof(buf), "Unknown MongoDB error, code %d", static_cast<int>(e));
return buf;
}
}
void MongoDB::Timer(void)
{
if (isDown && (MONGODB_RECONNECT_DELAY_MILLISECONDS <= stopwatch.Milliseconds()))
{
logprintf(Log::informational, "timer initiated MongoDB reconnect");
Reconnect();
}
}