removal of persistence in DS for static assignments

This commit is contained in:
Stephen Birarda 2014-01-30 14:33:36 -08:00
parent 740d11027c
commit 356222ba15
3 changed files with 252 additions and 381 deletions

View file

@ -8,9 +8,11 @@
#include <signal.h>
#include <QtCore/QDir>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtCore/QStandardPaths>
#include <QtCore/QStringList>
#include <QtCore/QTimer>
@ -27,64 +29,37 @@ const char* VOXEL_SERVER_CONFIG = "voxelServerConfig";
const char* PARTICLE_SERVER_CONFIG = "particleServerConfig";
const char* METAVOXEL_SERVER_CONFIG = "metavoxelServerConfig";
void signalhandler(int sig){
if (sig == SIGINT) {
qApp->quit();
}
}
const quint16 DOMAIN_SERVER_HTTP_PORT = 8080;
DomainServer::DomainServer(int argc, char* argv[]) :
QCoreApplication(argc, argv),
_HTTPManager(DOMAIN_SERVER_HTTP_PORT, QString("%1/resources/web/").arg(QCoreApplication::applicationDirPath()), this),
_staticAssignmentHash(),
_assignmentQueue(),
_staticAssignmentFile(QString("%1/config.ds").arg(QCoreApplication::applicationDirPath())),
_staticAssignmentFileData(NULL),
_voxelServerConfig(NULL),
_metavoxelServerConfig(NULL),
_hasCompletedRestartHold(false)
{
signal(SIGINT, signalhandler);
const char CUSTOM_PORT_OPTION[] = "-p";
const char* customPortString = getCmdOption(argc, (const char**) argv, CUSTOM_PORT_OPTION);
unsigned short domainServerPort = customPortString ? atoi(customPortString) : DEFAULT_DOMAIN_SERVER_PORT;
const char CONFIG_FILE_OPTION[] = "-c";
const char* configFilePath = getCmdOption(argc, (const char**) argv, CONFIG_FILE_OPTION);
if (!readConfigFile(configFilePath)) {
QByteArray voxelConfigOption = QString("--%1").arg(VOXEL_SERVER_CONFIG).toLocal8Bit();
_voxelServerConfig = getCmdOption(argc, (const char**) argv, voxelConfigOption.constData());
QByteArray particleConfigOption = QString("--%1").arg(PARTICLE_SERVER_CONFIG).toLocal8Bit();
_particleServerConfig = getCmdOption(argc, (const char**) argv, particleConfigOption.constData());
QByteArray metavoxelConfigOption = QString("--%1").arg(METAVOXEL_SERVER_CONFIG).toLocal8Bit();
_metavoxelServerConfig = getCmdOption(argc, (const char**) argv, metavoxelConfigOption.constData());
QStringList argumentList = arguments();
int argumentIndex = 0;
QSet<Assignment::Type> parsedTypes(QSet<Assignment::Type>() << Assignment::AgentType);
parseCommandLineTypeConfigs(argumentList, parsedTypes);
const QString CONFIG_FILE_OPTION = "--configFile";
if ((argumentIndex = argumentList.indexOf(CONFIG_FILE_OPTION)) != -1) {
QString configFilePath = argumentList.value(argumentIndex + 1);
readConfigFile(configFilePath, parsedTypes);
}
populateDefaultStaticAssignmentsExcludingTypes(parsedTypes);
NodeList* nodeList = NodeList::createInstance(NodeType::DomainServer, domainServerPort);
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), this, SLOT(nodeKilled(SharedNodePointer)));
if (!_staticAssignmentFile.exists() || _voxelServerConfig) {
if (_voxelServerConfig) {
// we have a new VS config, clear the existing file to start fresh
_staticAssignmentFile.remove();
}
prepopulateStaticAssignmentFile();
}
_staticAssignmentFile.open(QIODevice::ReadWrite);
_staticAssignmentFileData = _staticAssignmentFile.map(0, _staticAssignmentFile.size());
_staticAssignments = (Assignment*) _staticAssignmentFileData;
QTimer* silentNodeTimer = new QTimer(this);
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
@ -93,8 +68,145 @@ DomainServer::DomainServer(int argc, char* argv[]) :
// fire a single shot timer to add static assignments back into the queue after a restart
QTimer::singleShot(RESTART_HOLD_TIME_MSECS, this, SLOT(addStaticAssignmentsBackToQueueAfterRestart()));
}
connect(this, SIGNAL(aboutToQuit()), SLOT(cleanup()));
void DomainServer::parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes) {
// check for configs from the command line, these take precedence
const QString CONFIG_TYPE_OPTION = "--configType";
int clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION);
// enumerate all CL config overrides and parse them to files
while (clConfigIndex != -1) {
int clConfigType = argumentList.value(clConfigIndex + 1).toInt();
if (clConfigType < Assignment::AllTypes && !excludedTypes.contains((Assignment::Type) clConfigIndex)) {
Assignment::Type assignmentType = (Assignment::Type) clConfigType;
createStaticAssignmentsForTypeGivenConfigString((Assignment::Type) assignmentType,
argumentList.value(clConfigIndex + 2));
excludedTypes.insert(assignmentType);
}
clConfigIndex = argumentList.indexOf(CONFIG_TYPE_OPTION, clConfigIndex);
}
}
// Attempts to read configuration from specified path
// returns true on success, false otherwise
void DomainServer::readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes) {
if (path.isEmpty()) {
// config file not specified
return;
}
if (!QFile::exists(path)) {
qWarning("Specified configuration file does not exist!");
return;
}
QFile configFile(path);
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning("Can't open specified configuration file!");
return;
} else {
qDebug() << "Reading configuration from" << path;
}
QTextStream configStream(&configFile);
QByteArray configStringByteArray = configStream.readAll().toUtf8();
QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object();
configFile.close();
QSet<Assignment::Type> appendedExcludedTypes = excludedTypes;
foreach (const QString& rootStringValue, configDocObject.keys()) {
int possibleConfigType = rootStringValue.toInt();
if (possibleConfigType < Assignment::AllTypes
&& !excludedTypes.contains((Assignment::Type) possibleConfigType)) {
// this is an appropriate config type and isn't already in our excluded types
// we are good to parse it
Assignment::Type assignmentType = (Assignment::Type) possibleConfigType;
QString configString = readServerAssignmentConfig(configDocObject, rootStringValue);
createStaticAssignmentsForTypeGivenConfigString(assignmentType, configString);
excludedTypes.insert(assignmentType);
}
}
}
// find assignment configurations on the specified node name and json object
// returns a string in the form of its equivalent cmd line params
QString DomainServer::readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName) {
QJsonArray nodeArray = jsonObject[nodeName].toArray();
QStringList serverConfig;
foreach (const QJsonValue& childValue, nodeArray) {
QString cmdParams;
QJsonObject childObject = childValue.toObject();
QStringList keys = childObject.keys();
for (int i = 0; i < keys.size(); i++) {
QString key = keys[i];
QString value = childObject[key].toString();
// both cmd line params and json keys are the same
cmdParams += QString("--%1 %2 ").arg(key, value);
}
serverConfig << cmdParams;
}
// according to split() calls from DomainServer::prepopulateStaticAssignmentFile
// we shold simply join them with semicolons
return serverConfig.join(';');
}
void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment) {
qDebug() << "Inserting assignment" << *newAssignment << "to static assignment hash.";
_staticAssignmentHash.insert(newAssignment->getUUID(), SharedAssignmentPointer(newAssignment));
}
void DomainServer::createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString) {
// we have a string for config for this type
qDebug() << "Parsing command line config for assignment type" << type;
QString multiConfig(configString);
QStringList multiConfigList = multiConfig.split(";");
// read each config to a payload for this type of assignment
for (int i = 0; i < multiConfigList.size(); i++) {
QString config = multiConfigList.at(i);
qDebug("type %d config[%d] = %s", type, i, config.toLocal8Bit().constData());
// Now, parse the config to check for a pool
const QString ASSIGNMENT_CONFIG_POOL_OPTION = "--pool";
QString assignmentPool;
int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION);
if (poolIndex >= 0) {
int spaceBeforePoolIndex = config.indexOf(' ', poolIndex);
int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex);
assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex);
}
Assignment* configAssignment = new Assignment(Assignment::CreateCommand, type, assignmentPool);
configAssignment->setPayload(config.toUtf8());
addStaticAssignmentToAssignmentHash(configAssignment);
}
}
void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes) {
// enumerate over all assignment types and see if we've already excluded it
for (Assignment::Type defaultedType = Assignment::AudioMixerType; defaultedType != Assignment::AllTypes; defaultedType++) {
if (!excludedTypes.contains(defaultedType)) {
// type has not been set from a command line or config file config, use the default
// by clearing whatever exists and writing a single default assignment with no payload
Assignment* newAssignment = new Assignment(Assignment::CreateCommand, defaultedType);
addStaticAssignmentToAssignmentHash(newAssignment);
}
}
}
void DomainServer::readAvailableDatagrams() {
@ -147,13 +259,11 @@ void DomainServer::readAvailableDatagrams() {
<< NodeType::AvatarMixer << NodeType::VoxelServer << NodeType::ParticleServer
<< NodeType::MetavoxelServer;
Assignment* matchingStaticAssignment = NULL;
SharedAssignmentPointer matchingStaticAssignment;
if (!STATICALLY_ASSIGNED_NODES.contains(nodeType)
|| ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|| checkInWithUUIDMatchesExistingNode(nodePublicAddress,
nodeLocalAddress,
nodeUUID)))
|| (matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|| checkInWithUUIDMatchesExistingNode(nodePublicAddress, nodeLocalAddress, nodeUUID))
{
SharedNodePointer checkInNode = nodeList->addOrUpdateNode(nodeUUID,
nodeType,
@ -166,19 +276,13 @@ void DomainServer::readAvailableDatagrams() {
if (matchingStaticAssignment) {
// this was a newly added node with a matching static assignment
// remove the matching assignment from the assignment queue so we don't take the next check in
// (if it exists)
if (_hasCompletedRestartHold) {
// remove the matching assignment from the assignment queue so we don't take the next check in
removeAssignmentFromQueue(matchingStaticAssignment);
removeMatchingAssignmentFromQueue(matchingStaticAssignment);
}
// set the linked data for this node to a copy of the matching assignment
// so we can re-queue it should the node die
Assignment* nodeCopyOfMatchingAssignment = new Assignment(*matchingStaticAssignment);
checkInNode->setLinkedData(nodeCopyOfMatchingAssignment);
}
quint8 numInterestTypes = 0;
packetStream >> numInterestTypes;
@ -216,7 +320,7 @@ void DomainServer::readAvailableDatagrams() {
qDebug("Received a request for assignment type %i from %s.",
requestAssignment.getType(), qPrintable(senderSockAddr.getAddress().toString()));
Assignment* assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment);
if (assignmentToDeploy) {
// give this assignment out, either the type matches or the requestor said they will take any
@ -224,15 +328,10 @@ void DomainServer::readAvailableDatagrams() {
QDataStream assignmentStream(&assignmentPacket, QIODevice::Append);
assignmentStream << *assignmentToDeploy;
assignmentStream << assignmentToDeploy;
nodeList->getNodeSocket().writeDatagram(assignmentPacket,
senderSockAddr.getAddress(), senderSockAddr.getPort());
if (assignmentToDeploy->getNumberOfInstances() == 0) {
// there are no more instances of this script to send out, delete it
delete assignmentToDeploy;
}
}
} else {
@ -280,70 +379,6 @@ QJsonObject jsonObjectForNode(Node* node) {
return nodeJson;
}
// Attempts to read configuration from specified path
// returns true on success, false otherwise
bool DomainServer::readConfigFile(const char* path) {
if (!path) {
// config file not specified
return false;
}
if (!QFile::exists(path)) {
qWarning("Specified configuration file does not exist!\n");
return false;
}
QFile configFile(path);
if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning("Can't open specified configuration file!\n");
return false;
} else {
qDebug("Reading configuration from %s\n", path);
}
QTextStream configStream(&configFile);
QByteArray configStringByteArray = configStream.readAll().toUtf8();
QJsonObject configDocObject = QJsonDocument::fromJson(configStringByteArray).object();
configFile.close();
QString voxelServerConfig = readServerAssignmentConfig(configDocObject, VOXEL_SERVER_CONFIG);
_voxelServerConfig = new char[strlen(voxelServerConfig.toLocal8Bit().constData()) +1];
_voxelServerConfig = strcpy((char *) _voxelServerConfig, voxelServerConfig.toLocal8Bit().constData() + '\0');
QString particleServerConfig = readServerAssignmentConfig(configDocObject, PARTICLE_SERVER_CONFIG);
_particleServerConfig = new char[strlen(particleServerConfig.toLocal8Bit().constData()) +1];
_particleServerConfig = strcpy((char *) _particleServerConfig, particleServerConfig.toLocal8Bit().constData() + '\0');
QString metavoxelServerConfig = readServerAssignmentConfig(configDocObject, METAVOXEL_SERVER_CONFIG);
_metavoxelServerConfig = new char[strlen(metavoxelServerConfig.toLocal8Bit().constData()) +1];
_metavoxelServerConfig = strcpy((char *) _metavoxelServerConfig, metavoxelServerConfig.toLocal8Bit().constData() + '\0');
return true;
}
// find assignment configurations on the specified node name and json object
// returns a string in the form of its equivalent cmd line params
QString DomainServer::readServerAssignmentConfig(QJsonObject jsonObject, const char* nodeName) {
QJsonArray nodeArray = jsonObject[nodeName].toArray();
QStringList serverConfig;
foreach (const QJsonValue & childValue, nodeArray) {
QString cmdParams;
QJsonObject childObject = childValue.toObject();
QStringList keys = childObject.keys();
for (int i = 0; i < keys.size(); i++) {
QString key = keys[i];
QString value = childObject[key].toString();
// both cmd line params and json keys are the same
cmdParams += QString("--%1 %2 ").arg(key, value);
}
serverConfig << cmdParams;
}
// according to split() calls from DomainServer::prepopulateStaticAssignmentFile
// we shold simply join them with semicolons
return serverConfig.join(';');
}
bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString& path) {
const QString JSON_MIME_TYPE = "application/json";
@ -372,24 +407,19 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
QJsonObject queuedAssignmentsJSON;
// add the queued but unfilled assignments to the json
std::deque<Assignment*>::iterator assignment = _assignmentQueue.begin();
while (assignment != _assignmentQueue.end()) {
foreach(const SharedAssignmentPointer& assignment, _assignmentQueue) {
QJsonObject queuedAssignmentJSON;
QString uuidString = uuidStringWithoutCurlyBraces((*assignment)->getUUID());
queuedAssignmentJSON[JSON_KEY_TYPE] = QString((*assignment)->getTypeName());
QString uuidString = uuidStringWithoutCurlyBraces(assignment->getUUID());
queuedAssignmentJSON[JSON_KEY_TYPE] = QString(assignment->getTypeName());
// if the assignment has a pool, add it
if (!(*assignment)->getPool().isEmpty()) {
queuedAssignmentJSON[JSON_KEY_POOL] = (*assignment)->getPool();
if (!assignment->getPool().isEmpty()) {
queuedAssignmentJSON[JSON_KEY_POOL] = assignment->getPool();
}
// add this queued assignment to the JSON
queuedAssignmentsJSON[uuidString] = queuedAssignmentJSON;
// push forward the iterator to check the next assignment
assignment++;
}
assignmentJSON["queued"] = queuedAssignmentsJSON;
@ -427,11 +457,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
// this is a script upload - ask the HTTPConnection to parse the form data
QList<FormData> formData = connection->parseFormData();
// create an assignment for this saved script, for now make it local only
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand,
Assignment::AgentType,
NULL,
Assignment::LocalLocation);
// create an assignment for this saved script
Assignment* scriptAssignment = new Assignment(Assignment::CreateCommand, Assignment::AgentType);
// check how many instances of this assignment the user wants by checking the ASSIGNMENT-INSTANCES header
const QString ASSIGNMENT_INSTANCES_HEADER = "ASSIGNMENT-INSTANCES";
@ -465,8 +492,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
connection->respond(HTTPConnection::StatusCode200);
// add the script assigment to the assignment queue
// lock the assignment queue mutex since we're operating on a different thread than DS main
_assignmentQueue.push_back(scriptAssignment);
_assignmentQueue.enqueue(SharedAssignmentPointer(scriptAssignment));
}
} else if (connection->requestOperation() == QNetworkAccessManager::DeleteOperation) {
if (path.startsWith(URI_NODE)) {
@ -501,228 +527,99 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QString&
return false;
}
void DomainServer::addReleasedAssignmentBackToQueue(Assignment* releasedAssignment) {
qDebug() << "Adding assignment" << *releasedAssignment << " back to queue.";
// find this assignment in the static file
for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) {
if (_staticAssignments[i].getUUID() == releasedAssignment->getUUID()) {
// reset the UUID on the static assignment
_staticAssignments[i].resetUUID();
// put this assignment back in the queue so it goes out
_assignmentQueue.push_back(&_staticAssignments[i]);
} else if (_staticAssignments[i].getUUID().isNull()) {
// we are at the blank part of the static assignments - break out
break;
}
}
void DomainServer::refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment) {
QUuid oldUUID = assignment->getUUID();
assignment->resetUUID();
qDebug() << "Reset UUID for assignment -" << *assignment.data() << "- and added to queue. Old UUID was"
<< uuidStringWithoutCurlyBraces( oldUUID);
_assignmentQueue.enqueue(assignment);
}
void DomainServer::nodeKilled(SharedNodePointer node) {
// if this node has linked data it was from an assignment
if (node->getLinkedData()) {
Assignment* nodeAssignment = (Assignment*) node->getLinkedData();
addReleasedAssignmentBackToQueue(nodeAssignment);
// if this node's UUID matches a static assignment we need to throw it back in the assignment queue
SharedAssignmentPointer matchedAssignment = _staticAssignmentHash.value(node->getUUID());
if (matchedAssignment) {
refreshStaticAssignmentAndAddToQueue(matchedAssignment);
}
}
void DomainServer::prepopulateStaticAssignmentFile() {
int numFreshStaticAssignments = 0;
// write a fresh static assignment array to file
Assignment freshStaticAssignments[MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS];
// pre-populate the first static assignment list with assignments for root AuM, AvM, VS
freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AudioMixerType);
freshStaticAssignments[numFreshStaticAssignments++] = Assignment(Assignment::CreateCommand, Assignment::AvatarMixerType);
// Handle Domain/Voxel Server configuration command line arguments
if (_voxelServerConfig) {
qDebug("Reading Voxel Server Configuration.");
qDebug() << "config: " << _voxelServerConfig;
QString multiConfig((const char*) _voxelServerConfig);
QStringList multiConfigList = multiConfig.split(";");
// read each config to a payload for a VS assignment
for (int i = 0; i < multiConfigList.size(); i++) {
QString config = multiConfigList.at(i);
qDebug("config[%d]=%s", i, config.toLocal8Bit().constData());
// Now, parse the config to check for a pool
const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool";
QString assignmentPool;
int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION);
if (poolIndex >= 0) {
int spaceBeforePoolIndex = config.indexOf(' ', poolIndex);
int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex);
assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex);
qDebug() << "The pool for this voxel-assignment is" << assignmentPool;
}
Assignment voxelServerAssignment(Assignment::CreateCommand,
Assignment::VoxelServerType,
assignmentPool);
voxelServerAssignment.setPayload(config.toUtf8());
freshStaticAssignments[numFreshStaticAssignments++] = voxelServerAssignment;
}
} else {
Assignment rootVoxelServerAssignment(Assignment::CreateCommand, Assignment::VoxelServerType);
freshStaticAssignments[numFreshStaticAssignments++] = rootVoxelServerAssignment;
}
// Handle Domain/Particle Server configuration command line arguments
if (_particleServerConfig) {
qDebug("Reading Particle Server Configuration.");
qDebug() << "config: " << _particleServerConfig;
QString multiConfig((const char*) _particleServerConfig);
QStringList multiConfigList = multiConfig.split(";");
// read each config to a payload for a VS assignment
for (int i = 0; i < multiConfigList.size(); i++) {
QString config = multiConfigList.at(i);
qDebug("config[%d]=%s", i, config.toLocal8Bit().constData());
// Now, parse the config to check for a pool
const char ASSIGNMENT_CONFIG_POOL_OPTION[] = "--pool";
QString assignmentPool;
int poolIndex = config.indexOf(ASSIGNMENT_CONFIG_POOL_OPTION);
if (poolIndex >= 0) {
int spaceBeforePoolIndex = config.indexOf(' ', poolIndex);
int spaceAfterPoolIndex = config.indexOf(' ', spaceBeforePoolIndex);
assignmentPool = config.mid(spaceBeforePoolIndex + 1, spaceAfterPoolIndex);
qDebug() << "The pool for this particle-assignment is" << assignmentPool;
}
Assignment particleServerAssignment(Assignment::CreateCommand,
Assignment::ParticleServerType,
assignmentPool);
particleServerAssignment.setPayload(config.toLocal8Bit());
freshStaticAssignments[numFreshStaticAssignments++] = particleServerAssignment;
}
} else {
Assignment rootParticleServerAssignment(Assignment::CreateCommand, Assignment::ParticleServerType);
freshStaticAssignments[numFreshStaticAssignments++] = rootParticleServerAssignment;
}
// handle metavoxel configuration command line argument
Assignment& metavoxelAssignment = (freshStaticAssignments[numFreshStaticAssignments++] =
Assignment(Assignment::CreateCommand, Assignment::MetavoxelServerType));
if (_metavoxelServerConfig) {
metavoxelAssignment.setPayload(QByteArray(_metavoxelServerConfig));
}
qDebug() << "Adding" << numFreshStaticAssignments << "static assignments to fresh file.";
_staticAssignmentFile.open(QIODevice::WriteOnly);
_staticAssignmentFile.write((char*) &freshStaticAssignments, sizeof(freshStaticAssignments));
_staticAssignmentFile.resize(MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS * sizeof(Assignment));
_staticAssignmentFile.close();
}
Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
// pull the UUID passed with the check in
SharedAssignmentPointer DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType) {
if (_hasCompletedRestartHold) {
// iterate the assignment queue to check for a match
std::deque<Assignment*>::iterator assignment = _assignmentQueue.begin();
while (assignment != _assignmentQueue.end()) {
if ((*assignment)->getUUID() == checkInUUID) {
// return the matched assignment
return *assignment;
} else {
// no match, push deque iterator forwards
assignment++;
// look for a match in the assignment hash
QQueue<SharedAssignmentPointer>::iterator i = _assignmentQueue.begin();
while (i != _assignmentQueue.end()) {
if (i->data()->getType() == nodeType && i->data()->getUUID() == checkInUUID) {
return _assignmentQueue.takeAt(i - _assignmentQueue.begin());
}
}
} else {
for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) {
if (_staticAssignments[i].getUUID() == checkInUUID) {
// return matched assignment
return &_staticAssignments[i];
} else if (_staticAssignments[i].getUUID().isNull()) {
// end of static assignments, no match - return NULL
return NULL;
}
SharedAssignmentPointer matchingStaticAssignment = _staticAssignmentHash.value(checkInUUID);
if (matchingStaticAssignment && matchingStaticAssignment->getType() == nodeType) {
return matchingStaticAssignment;
}
}
return NULL;
return SharedAssignmentPointer();
}
Assignment* DomainServer::deployableAssignmentForRequest(Assignment& requestAssignment) {
SharedAssignmentPointer DomainServer::deployableAssignmentForRequest(const Assignment& requestAssignment) {
// this is an unassigned client talking to us directly for an assignment
// go through our queue and see if there are any assignments to give out
std::deque<Assignment*>::iterator assignment = _assignmentQueue.begin();
QQueue<SharedAssignmentPointer>::iterator sharedAssignment = _assignmentQueue.begin();
while (assignment != _assignmentQueue.end()) {
while (sharedAssignment != _assignmentQueue.end()) {
Assignment* assignment = sharedAssignment->data();
bool requestIsAllTypes = requestAssignment.getType() == Assignment::AllTypes;
bool assignmentTypesMatch = (*assignment)->getType() == requestAssignment.getType();
bool nietherHasPool = (*assignment)->getPool().isEmpty() && requestAssignment.getPool().isEmpty();
bool assignmentPoolsMatch = (*assignment)->getPool() == requestAssignment.getPool();
bool assignmentTypesMatch = assignment->getType() == requestAssignment.getType();
bool nietherHasPool = assignment->getPool().isEmpty() && requestAssignment.getPool().isEmpty();
bool assignmentPoolsMatch = assignment->getPool() == requestAssignment.getPool();
if ((requestIsAllTypes || assignmentTypesMatch) && (nietherHasPool || assignmentPoolsMatch)) {
Assignment* deployableAssignment = *assignment;
if ((*assignment)->getType() == Assignment::AgentType) {
if (assignment->getType() == Assignment::AgentType) {
// if there is more than one instance to send out, simply decrease the number of instances
if ((*assignment)->getNumberOfInstances() == 1) {
_assignmentQueue.erase(assignment);
if (assignment->getNumberOfInstances() == 1) {
return _assignmentQueue.takeAt(sharedAssignment - _assignmentQueue.begin());
} else {
assignment->decrementNumberOfInstances();
return *sharedAssignment;
}
deployableAssignment->decrementNumberOfInstances();
} else {
// remove the assignment from the queue
_assignmentQueue.erase(assignment);
SharedAssignmentPointer deployableAssignment = _assignmentQueue.takeAt(sharedAssignment
- _assignmentQueue.begin());
// until we get a check-in from that GUID
// put assignment back in queue but stick it at the back so the others have a chance to go out
_assignmentQueue.push_back(deployableAssignment);
_assignmentQueue.enqueue(deployableAssignment);
// stop looping, we've handed out an assignment
return deployableAssignment;
}
// stop looping, we've handed out an assignment
return deployableAssignment;
} else {
// push forward the iterator to check the next assignment
assignment++;
++sharedAssignment;
}
}
return NULL;
return SharedAssignmentPointer();
}
void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) {
std::deque<Assignment*>::iterator assignment = _assignmentQueue.begin();
while (assignment != _assignmentQueue.end()) {
if ((*assignment)->getUUID() == removableAssignment->getUUID()) {
_assignmentQueue.erase(assignment);
void DomainServer::removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment) {
QQueue<SharedAssignmentPointer>::iterator potentialMatchingAssignment = _assignmentQueue.begin();
while (potentialMatchingAssignment != _assignmentQueue.end()) {
if (potentialMatchingAssignment->data()->getUUID() == removableAssignment->getUUID()) {
_assignmentQueue.erase(potentialMatchingAssignment);
// we matched and removed an assignment, bail out
break;
} else {
// push forward the iterator to check the next assignment
assignment++;
++potentialMatchingAssignment;
}
}
}
@ -749,43 +646,24 @@ void DomainServer::addStaticAssignmentsBackToQueueAfterRestart() {
_hasCompletedRestartHold = true;
// if the domain-server has just restarted,
// check if there are static assignments in the file that we need to
// throw into the assignment queue
// pull anything in the static assignment file that isn't spoken for and add to the assignment queue
for (int i = 0; i < MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS; i++) {
if (_staticAssignments[i].getUUID().isNull()) {
// reached the end of static assignments, bail
break;
}
// check if there are static assignments that we need to throw into the assignment queue
QHash<QUuid, SharedAssignmentPointer>::iterator staticAssignment = _staticAssignmentHash.begin();
while (staticAssignment != _staticAssignmentHash.end()) {
// add any of the un-matched static assignments to the queue
bool foundMatchingAssignment = false;
NodeList* nodeList = NodeList::getInstance();
// enumerate the nodes and check if there is one with an attached assignment with matching UUID
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
if (node->getLinkedData()) {
Assignment* linkedAssignment = (Assignment*) node->getLinkedData();
if (linkedAssignment->getUUID() == _staticAssignments[i].getUUID()) {
foundMatchingAssignment = true;
break;
}
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
if (node->getUUID() == staticAssignment->data()->getUUID()) {
foundMatchingAssignment = true;
}
}
if (!foundMatchingAssignment) {
// this assignment has not been fulfilled - reset the UUID and add it to the assignment queue
_staticAssignments[i].resetUUID();
qDebug() << "Adding static assignment to queue -" << _staticAssignments[i];
_assignmentQueue.push_back(&_staticAssignments[i]);
refreshStaticAssignmentAndAddToQueue(*staticAssignment);
}
++staticAssignment;
}
}
void DomainServer::cleanup() {
_staticAssignmentFile.unmap(_staticAssignmentFileData);
_staticAssignmentFile.close();
}

View file

@ -9,17 +9,16 @@
#ifndef __hifi__DomainServer__
#define __hifi__DomainServer__
#include <deque>
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QMutex>
#include <QtCore/QHash>
#include <QtCore/QQueue>
#include <QtCore/QSharedPointer>
#include <Assignment.h>
#include <HTTPManager.h>
#include <NodeList.h>
const int MAX_STATIC_ASSIGNMENT_FILE_ASSIGNMENTS = 1000;
typedef QSharedPointer<Assignment> SharedAssignmentPointer;
class DomainServer : public QCoreApplication, public HTTPRequestHandler {
Q_OBJECT
@ -35,36 +34,30 @@ public slots:
void nodeKilled(SharedNodePointer node);
private:
bool readConfigFile(const char* path);
QString readServerAssignmentConfig(QJsonObject jsonObj, const char* nodeName);
void prepopulateStaticAssignmentFile();
Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType);
Assignment* deployableAssignmentForRequest(Assignment& requestAssignment);
void removeAssignmentFromQueue(Assignment* removableAssignment);
void parseCommandLineTypeConfigs(const QStringList& argumentList, QSet<Assignment::Type>& excludedTypes);
void readConfigFile(const QString& path, QSet<Assignment::Type>& excludedTypes);
QString readServerAssignmentConfig(const QJsonObject& jsonObject, const QString& nodeName);
void addStaticAssignmentToAssignmentHash(Assignment* newAssignment);
void createStaticAssignmentsForTypeGivenConfigString(Assignment::Type type, const QString& configString);
void populateDefaultStaticAssignmentsExcludingTypes(const QSet<Assignment::Type>& excludedTypes);
SharedAssignmentPointer matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NodeType_t nodeType);
SharedAssignmentPointer deployableAssignmentForRequest(const Assignment& requestAssignment);
void removeMatchingAssignmentFromQueue(const SharedAssignmentPointer& removableAssignment);
bool checkInWithUUIDMatchesExistingNode(const HifiSockAddr& nodePublicSocket,
const HifiSockAddr& nodeLocalSocket,
const QUuid& checkInUUI);
void addReleasedAssignmentBackToQueue(Assignment* releasedAssignment);
void refreshStaticAssignmentAndAddToQueue(SharedAssignmentPointer& assignment);
HTTPManager _HTTPManager;
std::deque<Assignment*> _assignmentQueue;
QFile _staticAssignmentFile;
uchar* _staticAssignmentFileData;
Assignment* _staticAssignments;
const char* _voxelServerConfig;
const char* _particleServerConfig;
const char* _metavoxelServerConfig;
QHash<QUuid, SharedAssignmentPointer> _staticAssignmentHash;
QQueue<SharedAssignmentPointer> _assignmentQueue;
bool _hasCompletedRestartHold;
private slots:
void readAvailableDatagrams();
void addStaticAssignmentsBackToQueueAfterRestart();
void cleanup();
};
#endif /* defined(__hifi__DomainServer__) */

View file

@ -144,7 +144,7 @@ const char* Assignment::getTypeName() const {
QDebug operator<<(QDebug debug, const Assignment &assignment) {
debug.nospace() << "UUID: " << qPrintable(assignment.getUUID().toString()) <<
", Type: " << assignment.getType();
return debug.nospace();
return debug.space();
}
QDataStream& operator<<(QDataStream &out, const Assignment& assignment) {