147 lines
4.6 KiB
C++
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();
|
|
}
|
|
}
|