mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-07-30 00:15:47 -04:00
Added TaskManager app
This commit is contained in:
@@ -0,0 +1,445 @@
|
||||
// ======================================================================
|
||||
//
|
||||
// Locator.cpp
|
||||
//
|
||||
// Copyright 2000-04 Sony Online Entertainment
|
||||
//
|
||||
// ======================================================================
|
||||
|
||||
#include "FirstTaskManager.h"
|
||||
#include "Locator.h"
|
||||
|
||||
#include "ConfigTaskManager.h"
|
||||
#include "ManagerConnection.h"
|
||||
#include "TaskManager.h"
|
||||
#include "serverNetworkMessages/TaskUtilization.h"
|
||||
#include "sharedFoundation/ConfigFile.h"
|
||||
#include "sharedLog/Log.h"
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
// ======================================================================
|
||||
|
||||
namespace LocatorNamespace
|
||||
{
|
||||
float getConfigSetting(const char *section, const char *key, const float defaultValue)
|
||||
{
|
||||
const ConfigFile::Section * sec = ConfigFile::getSection(section);
|
||||
if (sec == NULL)
|
||||
return defaultValue;
|
||||
|
||||
const ConfigFile::Key * ky = sec->findKey(key);
|
||||
if (ky == NULL)
|
||||
return defaultValue;
|
||||
|
||||
return ky->getAsFloat(ky->getCount()-1, defaultValue);
|
||||
}
|
||||
|
||||
struct PreferredNode
|
||||
{
|
||||
std::string m_nodeLabel;
|
||||
std::string m_processName;
|
||||
std::vector<std::string> m_nodeOptions;
|
||||
|
||||
bool match(std::string const &processName, std::string const &options) const
|
||||
{
|
||||
if (m_processName != processName)
|
||||
return false;
|
||||
for (std::vector<std::string>::const_iterator i = m_nodeOptions.begin(); i != m_nodeOptions.end(); ++i)
|
||||
if (options.find(*i) == std::string::npos)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ServerEntry
|
||||
{
|
||||
ServerEntry(ManagerConnection *conn, std::string const &label, float load);
|
||||
|
||||
bool operator==(std::string const &label) const
|
||||
{
|
||||
return m_label == label;
|
||||
}
|
||||
bool operator<(ServerEntry const & rhs) const
|
||||
{
|
||||
// don't change this; the code requires that the nodes
|
||||
// list be ordered by the current load on the node
|
||||
return m_load < rhs.m_load;
|
||||
}
|
||||
bool hasAvailableLoad(float cost) const
|
||||
{
|
||||
return ((m_load + cost) < m_maximumLoad);
|
||||
}
|
||||
|
||||
ManagerConnection *m_connection;
|
||||
std::string m_label;
|
||||
float m_load;
|
||||
float m_maximumLoad;
|
||||
};
|
||||
|
||||
ServerEntry::ServerEntry(ManagerConnection *conn, std::string const &label, float load) :
|
||||
m_connection(conn),
|
||||
m_label(label),
|
||||
m_load(load),
|
||||
m_maximumLoad(0.0f)
|
||||
{
|
||||
// see if there is a maximum load specified for this particular node
|
||||
char key[128];
|
||||
snprintf(key, sizeof(key)-1, "maximumLoad.%s", m_label.c_str());
|
||||
key[sizeof(key)-1] = '\0';
|
||||
|
||||
m_maximumLoad = getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad());
|
||||
}
|
||||
|
||||
std::vector<ServerEntry> s_serverList;
|
||||
const char s_masterNodeLabel[] = "node0";
|
||||
float s_myLoad;
|
||||
std::vector<PreferredNode> s_preferredNodes;
|
||||
std::map<std::string, std::string> s_closedConnections; // to keep track of TaskManager that we have lost connection to which has not yet reconnected
|
||||
|
||||
ManagerConnection *getPreferredServer(std::string const &processName, std::string const &options, float cost);
|
||||
ManagerConnection *getUnpreferredServer(float cost);
|
||||
void addPreferredNode(std::string const &preferredNodeSpec);
|
||||
}
|
||||
|
||||
using namespace LocatorNamespace;
|
||||
|
||||
// ======================================================================
|
||||
|
||||
void Locator::install()
|
||||
{
|
||||
int index = 0;
|
||||
char const * result = 0;
|
||||
|
||||
do
|
||||
{
|
||||
result = ConfigFile::getKeyString("TaskManager", "preferredNode", index++, 0);
|
||||
if (result)
|
||||
addPreferredNode(result);
|
||||
}
|
||||
while (result);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::closed(std::string const &label, ManagerConnection const *oldConnection)
|
||||
{
|
||||
if (oldConnection)
|
||||
{
|
||||
std::vector<ServerEntry>::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i != s_serverList.end())
|
||||
{
|
||||
DEBUG_REPORT_LOG(true, ("Removing connection %s on %s from locator map\n", label.c_str(), oldConnection->getRemoteAddress().c_str()));
|
||||
IGNORE_RETURN(s_serverList.erase(i));
|
||||
s_closedConnections[label] = oldConnection->getRemoteAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *LocatorNamespace::getPreferredServer(std::string const &processName, std::string const &options, float cost)
|
||||
{
|
||||
// Find a node other than the master node that can afford to run the process
|
||||
// and is a preferred node for the process and option set.
|
||||
for (std::vector<ServerEntry>::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i)
|
||||
{
|
||||
ServerEntry &e = *i;
|
||||
if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost)))
|
||||
{
|
||||
for (std::vector<PreferredNode>::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j)
|
||||
if ((*j).m_nodeLabel == e.m_label && (*j).match(processName, options))
|
||||
return e.m_connection;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *LocatorNamespace::getUnpreferredServer(float cost)
|
||||
{
|
||||
// Find a node other than the master node that can afford to run the process
|
||||
// and is a not marked as a preferred node for anything; if more than one
|
||||
// node qualifies, return the node with the lowest load
|
||||
for (std::vector<ServerEntry>::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i)
|
||||
{
|
||||
ServerEntry &e = *i;
|
||||
if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost)))
|
||||
{
|
||||
bool foundPreferred = false;
|
||||
for (std::vector<PreferredNode>::const_iterator j = s_preferredNodes.begin(); j != s_preferredNodes.end(); ++j)
|
||||
{
|
||||
if ((*j).m_nodeLabel == e.m_label)
|
||||
{
|
||||
foundPreferred = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// s_serverList is ordered by load, so this will
|
||||
// return the available node with the lowest load
|
||||
if (!foundPreferred)
|
||||
return e.m_connection;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *Locator::getBestServer(std::string const &processName, std::string const &options, float cost)
|
||||
{
|
||||
if (s_serverList.empty())
|
||||
return 0;
|
||||
|
||||
// first, look for a preferred node for this process
|
||||
{
|
||||
ManagerConnection * const connection = getPreferredServer(processName, options, cost);
|
||||
if (connection)
|
||||
return connection;
|
||||
}
|
||||
|
||||
// there is not a preferred node available, so look for a node which is not preferred in some form
|
||||
{
|
||||
ManagerConnection * const connection = getUnpreferredServer(cost);
|
||||
if (connection)
|
||||
return connection;
|
||||
}
|
||||
|
||||
// there is not a non-preferred node available, so look for any node other than the command node;
|
||||
// If more than one node qualifies, we want to choose the one who currently has the lowest load
|
||||
{
|
||||
for (std::vector<ServerEntry>::iterator i = s_serverList.begin(); i != s_serverList.end(); ++i)
|
||||
{
|
||||
ServerEntry &e = *i;
|
||||
if ((e.m_label != s_masterNodeLabel) && (e.hasAvailableLoad(cost)))
|
||||
{
|
||||
// s_serverList is ordered by load, so this will
|
||||
// return the available node with the lowest load
|
||||
return e.m_connection;
|
||||
}
|
||||
}
|
||||
|
||||
WARNING(true, ("No hosts are available to spawn a process costing %f without exceeding the host's load limit", cost));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
ManagerConnection *Locator::getServer(std::string const &label)
|
||||
{
|
||||
for (std::vector<ServerEntry>::const_iterator i = s_serverList.begin(); i != s_serverList.end(); ++i)
|
||||
if (i->m_label == label || i->m_connection->getRemoteAddress() == label)
|
||||
return i->m_connection;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float Locator::getServerLoad(std::string const &label)
|
||||
{
|
||||
std::vector<ServerEntry>::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i != s_serverList.end())
|
||||
return i->m_load;
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float Locator::getServerMaximumLoad(std::string const &label)
|
||||
{
|
||||
std::vector<ServerEntry>::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i != s_serverList.end())
|
||||
return i->m_maximumLoad;
|
||||
|
||||
// see if there is a maximum load specified for this particular node
|
||||
char key[128];
|
||||
snprintf(key, sizeof(key)-1, "maximumLoad.%s", label.c_str());
|
||||
key[sizeof(key)-1] = '\0';
|
||||
|
||||
return getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::incrementMyLoad(float amount)
|
||||
{
|
||||
s_myLoad += amount;
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::decrementMyLoad(float amount)
|
||||
{
|
||||
s_myLoad -= amount;
|
||||
if (s_myLoad < 0.0f)
|
||||
s_myLoad = 0.0f;
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
updateAllLoads(-amount);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::incrementServerLoad(std::string const &label, float amount)
|
||||
{
|
||||
std::vector<ServerEntry>::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i != s_serverList.end())
|
||||
{
|
||||
i->m_load += amount;
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::decrementServerLoad(std::string const &label, float amount)
|
||||
{
|
||||
std::vector<ServerEntry>::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i != s_serverList.end())
|
||||
{
|
||||
i->m_load -= amount;
|
||||
if (i->m_load < 0.0f)
|
||||
{
|
||||
DEBUG_WARNING(true, ("%s dropped less than 0", label.c_str()));
|
||||
i->m_load = 0.0f;
|
||||
}
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float Locator::getMyLoad()
|
||||
{
|
||||
return s_myLoad;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
float Locator::getMyMaximumLoad()
|
||||
{
|
||||
static float myMaximumLoad = -1.0f;
|
||||
|
||||
// get the maximum load for this particular node
|
||||
if (myMaximumLoad <= 0.0f)
|
||||
{
|
||||
// see if there is a maximum load specified for this particular node
|
||||
char key[128];
|
||||
snprintf(key, sizeof(key)-1, "maximumLoad.%s", TaskManager::getNodeLabel().c_str());
|
||||
key[sizeof(key)-1] = '\0';
|
||||
|
||||
myMaximumLoad = getConfigSetting("TaskManager", key, ConfigTaskManager::getMaximumLoad());
|
||||
}
|
||||
|
||||
return myMaximumLoad;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::opened(std::string const &label, ManagerConnection *newConnection)
|
||||
{
|
||||
if (newConnection)
|
||||
{
|
||||
std::vector<ServerEntry>::const_iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if (i == s_serverList.end())
|
||||
{
|
||||
ServerEntry s(newConnection, label, 0.0f);
|
||||
s_serverList.push_back(s);
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
IGNORE_RETURN(s_closedConnections.erase(label));
|
||||
|
||||
LOG("TaskManagerConnect", ("Connection with remote task manager %s established with label %s, maximum load %f", newConnection->getRemoteAddress().c_str(), label.c_str(), s.m_maximumLoad));
|
||||
}
|
||||
else
|
||||
{
|
||||
WARNING_STRICT_FATAL(true, ("Tried to add %s on %s to server list but it already exsists", label.c_str(), newConnection->getRemoteAddress().c_str()));
|
||||
}
|
||||
DEBUG_REPORT_LOG(true, ("Connection with remote task manager %s established with label %s\n", newConnection->getRemoteAddress().c_str(), label.c_str()));
|
||||
TaskManager::runSpawnRequestQueue();
|
||||
}
|
||||
else
|
||||
WARNING_STRICT_FATAL(true, ("Passed null connection to Locator::opened"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::updateServerLoad(std::string const &label, float load)
|
||||
{
|
||||
std::vector<ServerEntry>::iterator i = std::find(s_serverList.begin(), s_serverList.end(), label);
|
||||
if(i != s_serverList.end())
|
||||
{
|
||||
i->m_load += load;
|
||||
std::sort(s_serverList.begin(), s_serverList.end());
|
||||
LOG("TaskManager", ("updateServerLoad(%s, %f)", label.c_str(), load));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WARNING(true, ("Told to update load on %s which didn't exist\n", label.c_str()));
|
||||
}
|
||||
TaskManager::runSpawnRequestQueue();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::updateAllLoads(float delta)
|
||||
{
|
||||
if (!s_serverList.empty())
|
||||
{
|
||||
TaskUtilization const util(TaskUtilization::SYSTEM_AVG, delta);
|
||||
sendToAllTaskManagers(util);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
std::map<std::string, std::string> const & Locator::getClosedConnections()
|
||||
{
|
||||
return s_closedConnections;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void Locator::sendToAllTaskManagers(GameNetworkMessage const &msg)
|
||||
{
|
||||
if (!s_serverList.empty())
|
||||
for (std::vector<ServerEntry>::const_iterator i = s_serverList.begin(); i != s_serverList.end(); ++i)
|
||||
i->m_connection->send(msg);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
void LocatorNamespace::addPreferredNode(std::string const &preferredNodeSpec)
|
||||
{
|
||||
// preferredNodeSpec is "nodeLabel:processName:option=value:option=value:..."
|
||||
|
||||
PreferredNode n;
|
||||
std::string::size_type lastPos = 0;
|
||||
std::string::size_type pos;
|
||||
|
||||
pos = preferredNodeSpec.find(':', lastPos);
|
||||
n.m_nodeLabel = preferredNodeSpec.substr(lastPos, pos-lastPos);
|
||||
lastPos = pos == std::string::npos ? preferredNodeSpec.size() : pos+1;
|
||||
|
||||
pos = preferredNodeSpec.find(':', lastPos);
|
||||
n.m_processName = preferredNodeSpec.substr(lastPos, pos-lastPos);
|
||||
lastPos = pos == std::string::npos ? preferredNodeSpec.size() : pos+1;
|
||||
|
||||
while (lastPos != std::string::npos)
|
||||
{
|
||||
pos = preferredNodeSpec.find(':', lastPos);
|
||||
n.m_nodeOptions.push_back(preferredNodeSpec.substr(lastPos, pos-lastPos));
|
||||
lastPos = pos == std::string::npos ? std::string::npos : pos+1;
|
||||
}
|
||||
|
||||
if (!n.m_nodeLabel.empty() && !n.m_processName.empty())
|
||||
s_preferredNodes.push_back(n);
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
|
||||
Reference in New Issue
Block a user