mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 06:44:06 +02:00
AssignmentClientMonitor doesn't keep a list of its children. Instead it knows about active children due to their entries in the NodeList. Every few seconds, if 2 or more children are idle, the Monitor will ask one to exit
This commit is contained in:
parent
fd357c915c
commit
feb0e7ac31
7 changed files with 99 additions and 118 deletions
|
@ -18,7 +18,7 @@
|
|||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <Assignment.h>
|
||||
#include <AvatarHashMap.h>
|
||||
// #include <AvatarHashMap.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <LogHandler.h>
|
||||
#include <LogUtils.h>
|
||||
|
@ -41,7 +41,7 @@ SharedAssignmentPointer AssignmentClient::_currentAssignment;
|
|||
|
||||
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
|
||||
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) :
|
||||
AssignmentClient::AssignmentClient(int &argc, char **argv) :
|
||||
QCoreApplication(argc, argv),
|
||||
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME),
|
||||
_localASPortSharedMem(NULL),
|
||||
|
@ -58,8 +58,11 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) :
|
|||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
auto addressManager = DependencyManager::set<AddressManager>();
|
||||
auto nodeList = DependencyManager::set<NodeList>(NodeType::Unassigned);
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
// auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
|
||||
// make up a uuid for this child so the parent can tell us apart. This id will be changed
|
||||
// when the domain server hands over an assignment.
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
nodeList->setSessionUUID(nodeUUID);
|
||||
|
||||
// setup a shutdown event listener to handle SIGTERM or WM_CLOSE for us
|
||||
|
@ -139,11 +142,37 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, QUuid nodeUUID) :
|
|||
|
||||
// Create Singleton objects on main thread
|
||||
NetworkAccessManager::getInstance();
|
||||
// DependencyManager::get<NetworkAccessManager>();
|
||||
|
||||
setUpStatsToMonitor();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::stopAssignmentClient() {
|
||||
|
||||
// QList<QThread*> threads = QObject::findChildren <QThread*> ();
|
||||
// foreach(QThread *thread, threads) { // or FileUploader* fileuploader, fileUploaders_ ?
|
||||
// qDebug() << "thread " << thread->currentThreadId();
|
||||
// }
|
||||
|
||||
qDebug() << "Exiting.";
|
||||
|
||||
_requestTimer.stop();
|
||||
_statsTimerACM.stop();
|
||||
|
||||
|
||||
// DependencyManager::get<NodeList>()->disconnect();
|
||||
// DependencyManager::get<NodeList>()->disconnectNotify();
|
||||
// DependencyManager::get<AddressManager>()->disconnect();
|
||||
// DependencyManager::get<AddressManager>()->disconnectNotify();
|
||||
|
||||
// DependencyManager::destroy<NodeList>();
|
||||
// DependencyManager::destroy<AddressManager>();
|
||||
|
||||
quit();
|
||||
}
|
||||
|
||||
|
||||
void AssignmentClient::setUpStatsToMonitor() {
|
||||
// Figure out the address to send out stats to
|
||||
quint16 localMonitorServerPort = DEFAULT_ASSIGNMENT_CLIENT_MONITOR_PORT;
|
||||
|
@ -249,15 +278,12 @@ void AssignmentClient::readPendingDatagrams() {
|
|||
qDebug() << "Received an assignment that could not be unpacked. Re-requesting.";
|
||||
}
|
||||
} else if (packetTypeForPacket(receivedPacket) == PacketTypeStopNode) {
|
||||
qDebug() << "Network told me to exit";
|
||||
quit();
|
||||
qDebug() << "Network told me to exit.";
|
||||
emit stopAssignmentClient();
|
||||
} else {
|
||||
qDebug() << "punt";
|
||||
// have the NodeList attempt to handle it
|
||||
nodeList->processNodeData(senderSockAddr, receivedPacket);
|
||||
}
|
||||
} else {
|
||||
qDebug() << "packetVersionAndHashMatch said no";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class QSharedMemory;
|
|||
class AssignmentClient : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClient(int &argc, char **argv, QUuid nodeUUID);
|
||||
AssignmentClient(int &argc, char **argv);
|
||||
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
|
||||
|
||||
private slots:
|
||||
|
@ -30,6 +30,7 @@ private slots:
|
|||
void assignmentCompleted();
|
||||
void handleAuthenticationRequest();
|
||||
void sendStatsPacketToACM();
|
||||
void stopAssignmentClient();
|
||||
|
||||
private:
|
||||
void setUpStatsToMonitor();
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
|
||||
AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
||||
QApplication(argc, argv)
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
# ifndef WIN32
|
||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||
|
@ -40,9 +40,6 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
const QCommandLineOption numChildsOption("n", "number of children to fork", "child-count");
|
||||
parser.addOption(numChildsOption);
|
||||
|
||||
const QCommandLineOption idOption("i", "assignment client id", "uuid");
|
||||
parser.addOption(idOption);
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
|
@ -54,27 +51,16 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
|
|||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(numChildsOption) && parser.isSet(idOption)) {
|
||||
qCritical() << "using both -i and -n doesn't make sense.";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
unsigned int numForks = 0;
|
||||
if (parser.isSet(numChildsOption)) {
|
||||
numForks = parser.value(numChildsOption).toInt();
|
||||
}
|
||||
|
||||
QUuid nodeUUID = QUuid::createUuid();
|
||||
if (parser.isSet(idOption)) {
|
||||
nodeUUID = QUuid(parser.value(idOption));
|
||||
}
|
||||
|
||||
if (numForks) {
|
||||
AssignmentClientMonitor monitor(argc, argv, numForks);
|
||||
monitor.exec();
|
||||
} else {
|
||||
AssignmentClient client(argc, argv, nodeUUID);
|
||||
AssignmentClient client(argc, argv);
|
||||
client.exec();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
|
||||
class AssignmentClientApp : public QApplication {
|
||||
class AssignmentClientApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
AssignmentClientApp(int argc, char* argv[]);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "AssignmentClientMonitor.h"
|
||||
#include "PacketHeaders.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
const char* NUM_FORKS_PARAMETER = "-n";
|
||||
|
||||
|
@ -70,85 +71,49 @@ AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, const u
|
|||
|
||||
AssignmentClientMonitor::~AssignmentClientMonitor() {
|
||||
stopChildProcesses();
|
||||
|
||||
foreach (AssignmentClientChildData* childStatus, _childStatus) {
|
||||
delete childStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AssignmentClientMonitor::stopChildProcesses() {
|
||||
|
||||
QList<QPointer<QProcess> >::Iterator it = _childProcesses.begin();
|
||||
while (it != _childProcesses.end()) {
|
||||
if (!it->isNull()) {
|
||||
qDebug() << "Monitor is terminating child process" << it->data();
|
||||
|
||||
// don't re-spawn this child when it goes down
|
||||
disconnect(it->data(), 0, this, 0);
|
||||
|
||||
it->data()->terminate();
|
||||
it->data()->waitForFinished();
|
||||
}
|
||||
|
||||
it = _childProcesses.erase(it);
|
||||
}
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
qDebug() << "asking child" << node->getUUID() << "to exit.";
|
||||
node->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, *node->getActiveSocket());
|
||||
});
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::spawnChildClient() {
|
||||
QProcess *assignmentClient = new QProcess(this);
|
||||
|
||||
_childProcesses.append(QPointer<QProcess>(assignmentClient));
|
||||
|
||||
QUuid childUUID = QUuid::createUuid();
|
||||
|
||||
// create a Node for this child. this is done so we can idenitfy packets from unknown children
|
||||
DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(childUUID, NodeType::Unassigned, HifiSockAddr("localhost", 0), HifiSockAddr("localhost", 0), false);
|
||||
|
||||
// make sure that the output from the child process appears in our output
|
||||
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
|
||||
QStringList idArgs = QStringList() << "-i" << childUUID.toString();
|
||||
assignmentClient->start(applicationFilePath(), _childArguments + idArgs);
|
||||
|
||||
// link the child processes' finished slot to our childProcessFinished slot
|
||||
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
|
||||
SLOT(childProcessFinished(int, QProcess::ExitStatus)));
|
||||
|
||||
assignmentClient->start(applicationFilePath(), _childArguments);
|
||||
qDebug() << "Spawned a child client with PID" << assignmentClient->pid();
|
||||
}
|
||||
|
||||
void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug("Replacing dead child assignment client with a new one");
|
||||
|
||||
// remove the old process from our list of child processes
|
||||
qDebug() << "need to remove" << QPointer<QProcess>(qobject_cast<QProcess*>(sender()));
|
||||
_childProcesses.removeOne(QPointer<QProcess>(qobject_cast<QProcess*>(sender())));
|
||||
|
||||
spawnChildClient();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AssignmentClientMonitor::checkSpares() {
|
||||
qDebug() << "check spares:";
|
||||
|
||||
QString aSpareId = "";
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
QUuid aSpareId = "";
|
||||
unsigned int spareCount = 0;
|
||||
|
||||
QHash<QString, AssignmentClientChildData*>::const_iterator i = _childStatus.constBegin();
|
||||
while (i != _childStatus.constEnd()) {
|
||||
qDebug() << " " << i.key() << i.value()->getChildType();
|
||||
if (i.value()->getChildType() == "none") {
|
||||
spareCount ++;
|
||||
aSpareId = i.key();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
nodeList->removeSilentNodes();
|
||||
|
||||
qDebug() << "spare count is" << spareCount;
|
||||
qDebug() << "check spares:";
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node){
|
||||
AssignmentClientChildData *childData = static_cast<AssignmentClientChildData*>(node->getLinkedData());
|
||||
qDebug() << " " << node->getUUID() << childData->getChildType();
|
||||
if (childData->getChildType() == "none") {
|
||||
spareCount ++;
|
||||
aSpareId = node->getUUID();
|
||||
}
|
||||
});
|
||||
|
||||
qDebug() << " spare count is" << spareCount;
|
||||
|
||||
if (spareCount < 1) {
|
||||
qDebug() << "FORK";
|
||||
|
@ -156,13 +121,16 @@ void AssignmentClientMonitor::checkSpares() {
|
|||
}
|
||||
|
||||
if (spareCount > 1) {
|
||||
qDebug() << "KILL";
|
||||
// kill aSpareId
|
||||
qDebug() << "asking child" << aSpareId << "to exit.";
|
||||
SharedNodePointer childNode = nodeList->nodeWithUUID(aSpareId);
|
||||
childNode->activateLocalSocket();
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, childNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AssignmentClientMonitor::readPendingDatagrams() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
|
@ -176,16 +144,21 @@ void AssignmentClientMonitor::readPendingDatagrams() {
|
|||
|
||||
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
|
||||
if (packetTypeForPacket(receivedPacket) == PacketTypeNodeJsonStats) {
|
||||
|
||||
QUuid packetUUID = uuidFromPacketHeader(receivedPacket);
|
||||
// qDebug() << "packetUUID = " << packetUUID;
|
||||
|
||||
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
|
||||
if (!matchingNode) {
|
||||
qDebug() << "got packet from unknown child, id =" << packetUUID.toString();
|
||||
// tell unknown assignment-client child to exit.
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||
// XXX only do this if from local machine
|
||||
if (!packetUUID.isNull()) {
|
||||
matchingNode = DependencyManager::get<LimitedNodeList>()->addOrUpdateNode
|
||||
(packetUUID, NodeType::Unassigned, senderSockAddr, senderSockAddr, false);
|
||||
AssignmentClientChildData *childData = new AssignmentClientChildData("unknown");
|
||||
matchingNode->setLinkedData(childData);
|
||||
} else {
|
||||
// tell unknown assignment-client child to exit.
|
||||
qDebug() << "asking unknown child to exit.";
|
||||
QByteArray diePacket = byteArrayWithPopulatedHeader(PacketTypeStopNode);
|
||||
nodeList->writeUnverifiedDatagram(diePacket, senderSockAddr);
|
||||
}
|
||||
}
|
||||
|
||||
if (matchingNode) {
|
||||
|
@ -195,25 +168,18 @@ void AssignmentClientMonitor::readPendingDatagrams() {
|
|||
// push past the packet header
|
||||
QDataStream packetStream(receivedPacket);
|
||||
packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
|
||||
|
||||
// decode json
|
||||
QVariantMap unpackedVariantMap;
|
||||
|
||||
packetStream >> unpackedVariantMap;
|
||||
|
||||
QJsonObject unpackedStatsJSON = QJsonObject::fromVariantMap(unpackedVariantMap);
|
||||
|
||||
// qDebug() << "ACM got stats packet, id =" << packetUUID.toString()
|
||||
// << "type =" << unpackedStatsJSON["assignment_type"];
|
||||
|
||||
QString key(QString(packetUUID.toString()));
|
||||
if (_childStatus.contains(key)) {
|
||||
delete _childStatus[ key ];
|
||||
}
|
||||
|
||||
// get child's assignment type out of the decoded json
|
||||
QString childType = unpackedStatsJSON["assignment_type"].toString();
|
||||
auto childStatus = new AssignmentClientChildData(childType);
|
||||
_childStatus[ key ] = childStatus;
|
||||
|
||||
AssignmentClientChildData *childData =
|
||||
static_cast<AssignmentClientChildData*>(matchingNode->getLinkedData());
|
||||
childData->setChildType(childType);
|
||||
// note when this child talked
|
||||
matchingNode->setLastHeardMicrostamp(usecTimestampNow());
|
||||
}
|
||||
} else {
|
||||
// have the NodeList attempt to handle it
|
||||
|
|
|
@ -15,21 +15,25 @@
|
|||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QDateTime>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
||||
extern const char* NUM_FORKS_PARAMETER;
|
||||
|
||||
class AssignmentClientChildData {
|
||||
class AssignmentClientChildData : public NodeData {
|
||||
public:
|
||||
AssignmentClientChildData(QString childType);
|
||||
~AssignmentClientChildData();
|
||||
|
||||
QString getChildType() { return _childType; }
|
||||
void setChildType(QString childType) { _childType = childType; }
|
||||
|
||||
// implement parseData to return 0 so we can be a subclass of NodeData
|
||||
int parseData(const QByteArray& packet) { return 0; }
|
||||
|
||||
private:
|
||||
QString _childType;
|
||||
// ... timestamp
|
||||
};
|
||||
|
||||
|
||||
|
@ -41,17 +45,15 @@ public:
|
|||
|
||||
void stopChildProcesses();
|
||||
private slots:
|
||||
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
// void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
void readPendingDatagrams();
|
||||
void checkSpares();
|
||||
|
||||
private:
|
||||
void spawnChildClient();
|
||||
QList<QPointer<QProcess> > _childProcesses;
|
||||
// QList<QPointer<QProcess> > _childProcesses;
|
||||
|
||||
QStringList _childArguments;
|
||||
QHash<QString, AssignmentClientChildData*> _childStatus;
|
||||
|
||||
QTimer _checkSparesTimer; // every few seconds see if it need fewer or more spare children
|
||||
};
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
|||
pathString += "/" + orientationString;
|
||||
} else {
|
||||
qDebug() << "Cannot add orientation to path without a getter for position."
|
||||
<< "Call AdressManager::setOrientationGetter to pass a function that will return a glm::quat";
|
||||
<< "Call AddressManager::setOrientationGetter to pass a function that will return a glm::quat";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ const QString AddressManager::currentPath(bool withOrientation) const {
|
|||
return pathString;
|
||||
} else {
|
||||
qDebug() << "Cannot create address path without a getter for position."
|
||||
<< "Call AdressManager::setPositionGetter to pass a function that will return a const glm::vec3&";
|
||||
<< "Call AddressManager::setPositionGetter to pass a function that will return a const glm::vec3&";
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue