Merge pull request #950 from ZappoMan/multi_VS_assigments

Make VoxelServer class run as multiple instances
This commit is contained in:
Stephen Birarda 2013-09-17 17:43:33 -07:00
commit b6548303d1
15 changed files with 305 additions and 237 deletions

View file

@ -100,7 +100,6 @@ void childClient() {
// run the deployed assignment // run the deployed assignment
deployedAssignment->run(); deployedAssignment->run();
} else { } else {
qDebug("Received a bad destination socket for assignment.\n"); qDebug("Received a bad destination socket for assignment.\n");
} }
@ -154,6 +153,7 @@ void sigchldHandler(int sig) {
} }
} }
} }
} }
void parentMonitor() { void parentMonitor() {

View file

@ -27,6 +27,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QMap>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <civetweb.h> #include <civetweb.h>
@ -58,7 +59,7 @@ unsigned char* addNodeToBroadcastPacket(unsigned char* currentPosition, Node* no
} }
static int mongooseRequestHandler(struct mg_connection *conn) { static int mongooseRequestHandler(struct mg_connection *conn) {
const struct mg_request_info *ri = mg_get_request_info(conn); const struct mg_request_info* ri = mg_get_request_info(conn);
if (strcmp(ri->uri, "/assignment") == 0 && strcmp(ri->request_method, "POST") == 0) { if (strcmp(ri->uri, "/assignment") == 0 && strcmp(ri->request_method, "POST") == 0) {
// return a 200 // return a 200
@ -131,7 +132,7 @@ int main(int argc, const char* argv[]) {
in_addr_t serverLocalAddress = getLocalAddress(); in_addr_t serverLocalAddress = getLocalAddress();
nodeList->startSilentNodeRemovalThread(); nodeList->startSilentNodeRemovalThread();
timeval lastStatSendTime = {}; timeval lastStatSendTime = {};
const char ASSIGNMENT_SERVER_OPTION[] = "-a"; const char ASSIGNMENT_SERVER_OPTION[] = "-a";
@ -159,6 +160,15 @@ int main(int argc, const char* argv[]) {
Assignment voxelServerAssignment(Assignment::CreateCommand, Assignment voxelServerAssignment(Assignment::CreateCommand,
Assignment::VoxelServerType, Assignment::VoxelServerType,
Assignment::LocalLocation); Assignment::LocalLocation);
// Handle Domain/Voxel Server configuration command line arguments
const char VOXEL_CONFIG_OPTION[] = "--voxelServerConfig";
const char* voxelServerConfig = getCmdOption(argc, argv, VOXEL_CONFIG_OPTION);
if (voxelServerConfig) {
qDebug("Reading Voxel Server Configuration.\n");
qDebug() << " config: " << voxelServerConfig << "\n";
voxelServerAssignment.setPayload((uchar*)voxelServerConfig, strlen(voxelServerConfig) + 1);
}
// construct a local socket to send with our created assignments to the global AS // construct a local socket to send with our created assignments to the global AS
sockaddr_in localSocket = {}; sockaddr_in localSocket = {};
@ -167,13 +177,13 @@ int main(int argc, const char* argv[]) {
localSocket.sin_addr.s_addr = serverLocalAddress; localSocket.sin_addr.s_addr = serverLocalAddress;
// setup the mongoose web server // setup the mongoose web server
struct mg_context *ctx; struct mg_context* ctx;
struct mg_callbacks callbacks = {}; struct mg_callbacks callbacks = {};
QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath());
// list of options. Last element must be NULL. // list of options. Last element must be NULL.
const char *options[] = {"listening_ports", "8080", const char* options[] = {"listening_ports", "8080",
"document_root", documentRoot.toStdString().c_str(), NULL}; "document_root", documentRoot.toStdString().c_str(), NULL};
callbacks.begin_request = mongooseRequestHandler; callbacks.begin_request = mongooseRequestHandler;
@ -214,10 +224,9 @@ int main(int argc, const char* argv[]) {
} }
} }
const int MIN_VOXEL_SERVER_CHECKS = 10; const int MIN_VOXEL_SERVER_CHECKS = 10;
if (checkForVoxelServerAttempt > MIN_VOXEL_SERVER_CHECKS && if (checkForVoxelServerAttempt > MIN_VOXEL_SERVER_CHECKS && voxelServerCount == 0 &&
voxelServerCount == 0 &&
std::find(::assignmentQueue.begin(), ::assignmentQueue.end(), &voxelServerAssignment) == ::assignmentQueue.end()) { std::find(::assignmentQueue.begin(), ::assignmentQueue.end(), &voxelServerAssignment) == ::assignmentQueue.end()) {
qDebug("Missing a Voxel Server and assignment not in queue. Adding.\n"); qDebug("Missing a voxel server and assignment not in queue. Adding.\n");
::assignmentQueue.push_front(&voxelServerAssignment); ::assignmentQueue.push_front(&voxelServerAssignment);
} }
checkForVoxelServerAttempt++; checkForVoxelServerAttempt++;

View file

@ -165,12 +165,10 @@ int Assignment::packToBuffer(unsigned char* buffer) {
numPackedBytes += packSocket(buffer + numPackedBytes, socketToPack); numPackedBytes += packSocket(buffer + numPackedBytes, socketToPack);
} }
if (_numPayloadBytes) { if (_numPayloadBytes) {
memcpy(buffer + numPackedBytes, _payload, _numPayloadBytes); memcpy(buffer + numPackedBytes, _payload, _numPayloadBytes);
numPackedBytes += _numPayloadBytes; numPackedBytes += _numPayloadBytes;
} }
return numPackedBytes; return numPackedBytes;
} }

View file

@ -72,7 +72,7 @@ public:
const sockaddr* getAttachedLocalSocket() { return _attachedLocalSocket; } const sockaddr* getAttachedLocalSocket() { return _attachedLocalSocket; }
void setAttachedLocalSocket(const sockaddr* attachedLocalSocket); void setAttachedLocalSocket(const sockaddr* attachedLocalSocket);
/// Packs the assignment to the passed buffer /// Packs the assignment to the passed buffer
/// \param buffer the buffer in which to pack the assignment /// \param buffer the buffer in which to pack the assignment
/// \return number of bytes packed into buffer /// \return number of bytes packed into buffer

View file

@ -28,14 +28,17 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
_voxelPacketAt = _voxelPacket; _voxelPacketAt = _voxelPacket;
resetVoxelPacket(); resetVoxelPacket();
}
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
// Create voxel sending thread... // Create voxel sending thread...
uint16_t nodeID = getOwningNode()->getNodeID(); uint16_t nodeID = getOwningNode()->getNodeID();
_voxelSendThread = new VoxelSendThread(nodeID); _voxelSendThread = new VoxelSendThread(nodeID, voxelServer);
_voxelSendThread->initialize(true); _voxelSendThread->initialize(true);
} }
void VoxelNodeData::resetVoxelPacket() { void VoxelNodeData::resetVoxelPacket() {
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state. // the clients requested color state.
@ -57,8 +60,10 @@ void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) {
VoxelNodeData::~VoxelNodeData() { VoxelNodeData::~VoxelNodeData() {
delete[] _voxelPacket; delete[] _voxelPacket;
_voxelSendThread->terminate(); if (_voxelSendThread) {
delete _voxelSendThread; _voxelSendThread->terminate();
delete _voxelSendThread;
}
} }
bool VoxelNodeData::updateCurrentViewFrustum() { bool VoxelNodeData::updateCurrentViewFrustum() {

View file

@ -19,6 +19,7 @@
#include <VoxelSceneStats.h> #include <VoxelSceneStats.h>
class VoxelSendThread; class VoxelSendThread;
class VoxelServer;
class VoxelNodeData : public AvatarData { class VoxelNodeData : public AvatarData {
public: public:
@ -65,6 +66,9 @@ public:
VoxelSceneStats stats; VoxelSceneStats stats;
void initializeVoxelSendThread(VoxelServer* voxelServer);
bool isVoxelSendThreadInitalized() { return _voxelSendThread; }
private: private:
VoxelNodeData(const VoxelNodeData &); VoxelNodeData(const VoxelNodeData &);
VoxelNodeData& operator= (const VoxelNodeData&); VoxelNodeData& operator= (const VoxelNodeData&);

View file

@ -16,10 +16,11 @@ extern EnvironmentData environmentData[3];
#include "VoxelSendThread.h" #include "VoxelSendThread.h"
#include "VoxelServer.h" #include "VoxelServer.h"
#include "VoxelServerState.h" #include "VoxelServerConsts.h"
VoxelSendThread::VoxelSendThread(uint16_t nodeID) : VoxelSendThread::VoxelSendThread(uint16_t nodeID, VoxelServer* myServer) :
_nodeID(nodeID) { _nodeID(nodeID),
_myServer(myServer) {
} }
bool VoxelSendThread::process() { bool VoxelSendThread::process() {
@ -35,7 +36,7 @@ bool VoxelSendThread::process() {
// Sometimes the node data has not yet been linked, in which case we can't really do anything // Sometimes the node data has not yet been linked, in which case we can't really do anything
if (nodeData) { if (nodeData) {
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
} }
deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
@ -47,7 +48,7 @@ bool VoxelSendThread::process() {
if (usecToSleep > 0) { if (usecToSleep > 0) {
usleep(usecToSleep); usleep(usecToSleep);
} else { } else {
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
std::cout << "Last send took too much time, not sleeping!\n"; std::cout << "Last send took too much time, not sleeping!\n";
} }
} }
@ -94,7 +95,7 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
/// Version of voxel distributor that sends the deepest LOD level at once /// Version of voxel distributor that sends the deepest LOD level at once
void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) {
pthread_mutex_lock(&::treeLock); _myServer->lockTree();
int truePacketsSent = 0; int truePacketsSent = 0;
int trueBytesSent = 0; int trueBytesSent = 0;
@ -113,7 +114,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
if (wantColor != nodeData->getCurrentPacketIsColor()) { if (wantColor != nodeData->getCurrentPacketIsColor()) {
if (nodeData->isPacketWaiting()) { if (nodeData->isPacketWaiting()) {
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n", printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
} }
@ -121,7 +122,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
} else { } else {
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
} }
@ -129,7 +130,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
} }
} }
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n", printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
@ -137,7 +138,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", printf("deepestLevelVoxelDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n",
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()),
debug::valueOf(nodeData->getViewSent()) debug::valueOf(nodeData->getViewSent())
@ -148,7 +149,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
// the current view frustum for things to send. // the current view frustum for things to send.
if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) {
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n",
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()));
if (nodeData->getLastTimeBagEmpty() > 0) { if (nodeData->getLastTimeBagEmpty() > 0) {
@ -166,7 +167,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
// if our view has changed, we need to reset these things... // if our view has changed, we need to reset these things...
if (viewFrustumChanged) { if (viewFrustumChanged) {
if (::dumpVoxelsOnMove) { if (_myServer->wantDumpVoxelsOnMove()) {
nodeData->nodeBag.deleteAll(); nodeData->nodeBag.deleteAll();
} }
nodeData->map.erase(); nodeData->map.erase();
@ -180,7 +181,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
nodeData->stats.sceneCompleted(); nodeData->stats.sceneCompleted();
if (::displayVoxelStats) { if (_myServer->wantDisplayVoxelStats()) {
nodeData->stats.printDebugDetails(); nodeData->stats.printDebugDetails();
} }
@ -191,10 +192,10 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
if (isFullScene) { if (isFullScene) {
nodeData->nodeBag.deleteAll(); nodeData->nodeBag.deleteAll();
} }
nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, ::serverTree.rootNode, ::jurisdiction); nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getServerTree().rootNode, _myServer->getJurisdiction());
// This is the start of "resending" the scene. // This is the start of "resending" the scene.
nodeData->nodeBag.insert(serverTree.rootNode); nodeData->nodeBag.insert(_myServer->getServerTree().rootNode);
} }
// If we have something in our nodeBag, then turn them into packets and send them out... // If we have something in our nodeBag, then turn them into packets and send them out...
@ -203,8 +204,8 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
int packetsSentThisInterval = 0; int packetsSentThisInterval = 0;
uint64_t start = usecTimestampNow(); uint64_t start = usecTimestampNow();
bool shouldSendEnvironments = ::sendEnvironments && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { while (packetsSentThisInterval < _myServer->getPacketsPerClientPerInterval() - (shouldSendEnvironments ? 1 : 0)) {
// Check to see if we're taking too long, and if so bail early... // Check to see if we're taking too long, and if so bail early...
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
long elapsedUsec = (now - start); long elapsedUsec = (now - start);
@ -212,7 +213,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec); long usecRemaining = (VOXEL_SEND_INTERVAL_USECS - elapsedUsec);
if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) { if (elapsedUsecPerPacket + SENDING_TIME_TO_SPARE > usecRemaining) {
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n", printf("packetLoop() usecRemaining=%ld bailing early took %ld usecs to generate %d bytes in %d packets (%ld usec avg), %d nodes still to send\n",
usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket, usecRemaining, elapsedUsec, trueBytesSent, truePacketsSent, elapsedUsecPerPacket,
nodeData->nodeBag.count()); nodeData->nodeBag.count());
@ -234,10 +235,10 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap, boundaryLevelAdjust, wantOcclusionCulling, coverageMap, boundaryLevelAdjust,
nodeData->getLastTimeBagEmpty(), nodeData->getLastTimeBagEmpty(),
isFullScene, &nodeData->stats, ::jurisdiction); isFullScene, &nodeData->stats, _myServer->getJurisdiction());
nodeData->stats.encodeStarted(); nodeData->stats.encodeStarted();
bytesWritten = serverTree.encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1, bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params); nodeData->nodeBag, params);
nodeData->stats.encodeStopped(); nodeData->stats.encodeStopped();
@ -254,17 +255,17 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
} }
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left
} }
} }
// send the environment packet // send the environment packet
if (shouldSendEnvironments) { if (shouldSendEnvironments) {
int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA); int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
int envPacketLength = numBytesPacketHeader; int envPacketLength = numBytesPacketHeader;
int environmentsToSend = ::sendMinimalEnvironment ? 1 : sizeof(environmentData) / sizeof(EnvironmentData); int environmentsToSend = _myServer->getSendMinimalEnvironment() ? 1 : _myServer->getEnvironmentDataCount();
for (int i = 0; i < environmentsToSend; i++) { for (int i = 0; i < environmentsToSend; i++) {
envPacketLength += environmentData[i].getBroadcastData(_tempOutputBuffer + envPacketLength); envPacketLength += _myServer->getEnvironmentData(i)->getBroadcastData(_tempOutputBuffer + envPacketLength);
} }
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength); NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength);
@ -283,7 +284,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", printf("WARNING! packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
} }
} else if (::debugVoxelSending) { } else if (_myServer->wantsDebugVoxelSending()) {
printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n", printf("packetLoop() took %d milliseconds to generate %d bytes in %d packets, %d nodes still to send\n",
elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); elapsedmsec, trueBytesSent, truePacketsSent, nodeData->nodeBag.count());
} }
@ -293,7 +294,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
if (nodeData->nodeBag.isEmpty()) { if (nodeData->nodeBag.isEmpty()) {
nodeData->updateLastKnownViewFrustum(); nodeData->updateLastKnownViewFrustum();
nodeData->setViewSent(true); nodeData->setViewSent(true);
if (::debugVoxelSending) { if (_myServer->wantsDebugVoxelSending()) {
nodeData->map.printStats(); nodeData->map.printStats();
} }
nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes
@ -301,6 +302,6 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
} // end if bag wasn't empty, and so we sent stuff... } // end if bag wasn't empty, and so we sent stuff...
pthread_mutex_unlock(&::treeLock); _myServer->unlockTree();
} }

View file

@ -16,17 +16,19 @@
#include <VoxelTree.h> #include <VoxelTree.h>
#include <VoxelNodeBag.h> #include <VoxelNodeBag.h>
#include "VoxelNodeData.h" #include "VoxelNodeData.h"
#include "VoxelServer.h"
/// Threaded processor for sending voxel packets to a single client /// Threaded processor for sending voxel packets to a single client
class VoxelSendThread : public virtual GenericThread { class VoxelSendThread : public virtual GenericThread {
public: public:
VoxelSendThread(uint16_t nodeID); VoxelSendThread(uint16_t nodeID, VoxelServer* myServer);
protected: protected:
/// Implements generic processing behavior for this thread. /// Implements generic processing behavior for this thread.
virtual bool process(); virtual bool process();
private: private:
uint16_t _nodeID; uint16_t _nodeID;
VoxelServer* _myServer;
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent); void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
void deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged); void deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);

View file

@ -14,7 +14,6 @@
#include <OctalCode.h> #include <OctalCode.h>
#include <NodeList.h> #include <NodeList.h>
#include <NodeTypes.h> #include <NodeTypes.h>
#include <EnvironmentData.h>
#include <VoxelTree.h> #include <VoxelTree.h>
#include "VoxelNodeData.h" #include "VoxelNodeData.h"
#include <SharedUtil.h> #include <SharedUtil.h>
@ -23,11 +22,6 @@
#include <PerfStat.h> #include <PerfStat.h>
#include <JurisdictionSender.h> #include <JurisdictionSender.h>
#include "NodeWatcher.h"
#include "VoxelPersistThread.h"
#include "VoxelSendThread.h"
#include "VoxelServerPacketProcessor.h"
#ifdef _WIN32 #ifdef _WIN32
#include "Syssocket.h" #include "Syssocket.h"
#include "Systime.h" #include "Systime.h"
@ -38,34 +32,10 @@
#endif #endif
#include "VoxelServer.h" #include "VoxelServer.h"
#include "VoxelServerState.h" #include "VoxelServerConsts.h"
const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo";
const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo";
char voxelPersistFilename[MAX_FILENAME_LENGTH];
int PACKETS_PER_CLIENT_PER_INTERVAL = 10;
VoxelTree serverTree(true); // this IS a reaveraging tree
bool wantVoxelPersist = true;
bool wantLocalDomain = false;
bool debugVoxelSending = false;
bool shouldShowAnimationDebug = false;
bool displayVoxelStats = false;
bool debugVoxelReceiving = false;
bool sendEnvironments = true;
bool sendMinimalEnvironment = false;
bool dumpVoxelsOnMove = false;
EnvironmentData environmentData[3];
int receivedPacketCount = 0;
JurisdictionMap* jurisdiction = NULL;
JurisdictionSender* jurisdictionSender = NULL;
VoxelServerPacketProcessor* voxelServerPacketProcessor = NULL;
VoxelPersistThread* voxelPersistThread = NULL;
pthread_mutex_t treeLock;
NodeWatcher nodeWatcher; // used to cleanup AGENT data when agents are killed
int VoxelServer::_argc = 0;
const char** VoxelServer::_argv = NULL;
bool VoxelServer::_dontKillOnMissingDomain = false;
void attachVoxelNodeDataToNode(Node* newNode) { void attachVoxelNodeDataToNode(Node* newNode) {
if (newNode->getLinkedData() == NULL) { if (newNode->getLinkedData() == NULL) {
@ -74,12 +44,48 @@ void attachVoxelNodeDataToNode(Node* newNode) {
} }
VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) : VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) :
Assignment(command, Assignment::VoxelServerType, location) { Assignment(command, Assignment::VoxelServerType, location),
_serverTree(true) {
_argc = 0;
_argv = NULL;
_dontKillOnMissingDomain = false;
_packetsPerClientPerInterval = 10;
_wantVoxelPersist = true;
_wantLocalDomain = false;
_debugVoxelSending = false;
_shouldShowAnimationDebug = false;
_displayVoxelStats = false;
_debugVoxelReceiving = false;
_sendEnvironments = true;
_sendMinimalEnvironment = false;
_dumpVoxelsOnMove = false;
_jurisdiction = NULL;
_jurisdictionSender = NULL;
_voxelServerPacketProcessor = NULL;
_voxelPersistThread = NULL;
} }
VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) { VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes),
_serverTree(true) {
_argc = 0;
_argv = NULL;
_dontKillOnMissingDomain = false;
_packetsPerClientPerInterval = 10;
_wantVoxelPersist = true;
_wantLocalDomain = false;
_debugVoxelSending = false;
_shouldShowAnimationDebug = false;
_displayVoxelStats = false;
_debugVoxelReceiving = false;
_sendEnvironments = true;
_sendMinimalEnvironment = false;
_dumpVoxelsOnMove = false;
_jurisdiction = NULL;
_jurisdictionSender = NULL;
_voxelServerPacketProcessor = NULL;
_voxelPersistThread = NULL;
} }
void VoxelServer::setArguments(int argc, char** argv) { void VoxelServer::setArguments(int argc, char** argv) {
@ -87,13 +93,13 @@ void VoxelServer::setArguments(int argc, char** argv) {
_argv = const_cast<const char**>(argv); _argv = const_cast<const char**>(argv);
} }
void VoxelServer::setupDomainAndPort(const char* domain, int port) { void VoxelServer::setupStandAlone(const char* domain, int port) {
NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, port); NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, port);
// Handle Local Domain testing with the --local command line // Handle Local Domain testing with the --local command line
const char* local = "--local"; const char* local = "--local";
::wantLocalDomain = strcmp(domain, local) == 0; _wantLocalDomain = strcmp(domain, local) == 0;
if (::wantLocalDomain) { if (_wantLocalDomain) {
printf("Local Domain MODE!\n"); printf("Local Domain MODE!\n");
NodeList::getInstance()->setDomainIPToLocalhost(); NodeList::getInstance()->setDomainIPToLocalhost();
} else { } else {
@ -108,7 +114,7 @@ void VoxelServer::setupDomainAndPort(const char* domain, int port) {
//int main(int argc, const char * argv[]) { //int main(int argc, const char * argv[]) {
void VoxelServer::run() { void VoxelServer::run() {
pthread_mutex_init(&::treeLock, NULL); pthread_mutex_init(&_treeLock, NULL);
qInstallMessageHandler(sharedMessageHandler); qInstallMessageHandler(sharedMessageHandler);
@ -118,7 +124,7 @@ void VoxelServer::run() {
printf("jurisdictionFile=%s\n", jurisdictionFile); printf("jurisdictionFile=%s\n", jurisdictionFile);
printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); printf("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
jurisdiction = new JurisdictionMap(jurisdictionFile); _jurisdiction = new JurisdictionMap(jurisdictionFile);
printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); printf("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile);
} else { } else {
const char* JURISDICTION_ROOT = "--jurisdictionRoot"; const char* JURISDICTION_ROOT = "--jurisdictionRoot";
@ -134,28 +140,28 @@ void VoxelServer::run() {
} }
if (jurisdictionRoot || jurisdictionEndNodes) { if (jurisdictionRoot || jurisdictionEndNodes) {
::jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); _jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
} }
} }
// should we send environments? Default is yes, but this command line suppresses sending // should we send environments? Default is yes, but this command line suppresses sending
const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove"; const char* DUMP_VOXELS_ON_MOVE = "--dumpVoxelsOnMove";
::dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE); _dumpVoxelsOnMove = cmdOptionExists(_argc, _argv, DUMP_VOXELS_ON_MOVE);
printf("dumpVoxelsOnMove=%s\n", debug::valueOf(::dumpVoxelsOnMove)); printf("dumpVoxelsOnMove=%s\n", debug::valueOf(_dumpVoxelsOnMove));
// should we send environments? Default is yes, but this command line suppresses sending // should we send environments? Default is yes, but this command line suppresses sending
const char* DONT_SEND_ENVIRONMENTS = "--dontSendEnvironments"; const char* DONT_SEND_ENVIRONMENTS = "--dontSendEnvironments";
bool dontSendEnvironments = getCmdOption(_argc, _argv, DONT_SEND_ENVIRONMENTS); bool dontSendEnvironments = getCmdOption(_argc, _argv, DONT_SEND_ENVIRONMENTS);
if (dontSendEnvironments) { if (dontSendEnvironments) {
printf("Sending environments suppressed...\n"); printf("Sending environments suppressed...\n");
::sendEnvironments = false; _sendEnvironments = false;
} else { } else {
// should we send environments? Default is yes, but this command line suppresses sending // should we send environments? Default is yes, but this command line suppresses sending
const char* MINIMAL_ENVIRONMENT = "--MinimalEnvironment"; const char* MINIMAL_ENVIRONMENT = "--MinimalEnvironment";
::sendMinimalEnvironment = getCmdOption(_argc, _argv, MINIMAL_ENVIRONMENT); _sendMinimalEnvironment = getCmdOption(_argc, _argv, MINIMAL_ENVIRONMENT);
printf("Using Minimal Environment=%s\n", debug::valueOf(::sendMinimalEnvironment)); printf("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment));
} }
printf("Sending environments=%s\n", debug::valueOf(::sendEnvironments)); printf("Sending environments=%s\n", debug::valueOf(_sendEnvironments));
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER); nodeList->setOwnerType(NODE_TYPE_VOXEL_SERVER);
@ -163,72 +169,72 @@ void VoxelServer::run() {
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
// tell our NodeList about our desire to get notifications // tell our NodeList about our desire to get notifications
nodeList->addHook(&nodeWatcher); nodeList->addHook(&_nodeWatcher);
nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode; nodeList->linkedDataCreateCallback = &attachVoxelNodeDataToNode;
nodeList->startSilentNodeRemovalThread(); nodeList->startSilentNodeRemovalThread();
srand((unsigned)time(0)); srand((unsigned)time(0));
const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats"; const char* DISPLAY_VOXEL_STATS = "--displayVoxelStats";
::displayVoxelStats = getCmdOption(_argc, _argv, DISPLAY_VOXEL_STATS); _displayVoxelStats = getCmdOption(_argc, _argv, DISPLAY_VOXEL_STATS);
printf("displayVoxelStats=%s\n", debug::valueOf(::displayVoxelStats)); printf("displayVoxelStats=%s\n", debug::valueOf(_displayVoxelStats));
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending"; const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
::debugVoxelSending = getCmdOption(_argc, _argv, DEBUG_VOXEL_SENDING); _debugVoxelSending = getCmdOption(_argc, _argv, DEBUG_VOXEL_SENDING);
printf("debugVoxelSending=%s\n", debug::valueOf(::debugVoxelSending)); printf("debugVoxelSending=%s\n", debug::valueOf(_debugVoxelSending));
const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving"; const char* DEBUG_VOXEL_RECEIVING = "--debugVoxelReceiving";
::debugVoxelReceiving = getCmdOption(_argc, _argv, DEBUG_VOXEL_RECEIVING); _debugVoxelReceiving = getCmdOption(_argc, _argv, DEBUG_VOXEL_RECEIVING);
printf("debugVoxelReceiving=%s\n", debug::valueOf(::debugVoxelReceiving)); printf("debugVoxelReceiving=%s\n", debug::valueOf(_debugVoxelReceiving));
const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug"; const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug";
::shouldShowAnimationDebug = getCmdOption(_argc, _argv, WANT_ANIMATION_DEBUG); _shouldShowAnimationDebug = getCmdOption(_argc, _argv, WANT_ANIMATION_DEBUG);
printf("shouldShowAnimationDebug=%s\n", debug::valueOf(::shouldShowAnimationDebug)); printf("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug));
// By default we will voxel persist, if you want to disable this, then pass in this parameter // By default we will voxel persist, if you want to disable this, then pass in this parameter
const char* NO_VOXEL_PERSIST = "--NoVoxelPersist"; const char* NO_VOXEL_PERSIST = "--NoVoxelPersist";
if ( getCmdOption(_argc, _argv, NO_VOXEL_PERSIST)) { if (getCmdOption(_argc, _argv, NO_VOXEL_PERSIST)) {
::wantVoxelPersist = false; _wantVoxelPersist = false;
} }
printf("wantVoxelPersist=%s\n", debug::valueOf(::wantVoxelPersist)); printf("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist));
// if we want Voxel Persistence, load the local file now... // if we want Voxel Persistence, load the local file now...
bool persistantFileRead = false; bool persistantFileRead = false;
if (::wantVoxelPersist) { if (_wantVoxelPersist) {
// Check to see if the user passed in a command line option for setting packet send rate // Check to see if the user passed in a command line option for setting packet send rate
const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename"; const char* VOXELS_PERSIST_FILENAME = "--voxelsPersistFilename";
const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME); const char* voxelsPersistFilenameParameter = getCmdOption(_argc, _argv, VOXELS_PERSIST_FILENAME);
if (voxelsPersistFilenameParameter) { if (voxelsPersistFilenameParameter) {
strcpy(voxelPersistFilename, voxelsPersistFilenameParameter); strcpy(_voxelPersistFilename, voxelsPersistFilenameParameter);
} else { } else {
//strcpy(voxelPersistFilename, ::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); //strcpy(voxelPersistFilename, _wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE);
strcpy(voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE); strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE);
} }
printf("loading voxels from file: %s...\n", voxelPersistFilename); printf("loading voxels from file: %s...\n", _voxelPersistFilename);
persistantFileRead = ::serverTree.readFromSVOFile(::voxelPersistFilename); persistantFileRead = _serverTree.readFromSVOFile(_voxelPersistFilename);
if (persistantFileRead) { if (persistantFileRead) {
PerformanceWarning warn(::shouldShowAnimationDebug, PerformanceWarning warn(_shouldShowAnimationDebug,
"persistVoxelsWhenDirty() - reaverageVoxelColors()", ::shouldShowAnimationDebug); "persistVoxelsWhenDirty() - reaverageVoxelColors()", _shouldShowAnimationDebug);
// after done inserting all these voxels, then reaverage colors // after done inserting all these voxels, then reaverage colors
serverTree.reaverageVoxelColors(serverTree.rootNode); _serverTree.reaverageVoxelColors(_serverTree.rootNode);
printf("Voxels reAveraged\n"); printf("Voxels reAveraged\n");
} }
::serverTree.clearDirtyBit(); // the tree is clean since we just loaded it _serverTree.clearDirtyBit(); // the tree is clean since we just loaded it
printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
unsigned long nodeCount = ::serverTree.rootNode->getSubTreeNodeCount(); unsigned long nodeCount = _serverTree.rootNode->getSubTreeNodeCount();
unsigned long internalNodeCount = ::serverTree.rootNode->getSubTreeInternalNodeCount(); unsigned long internalNodeCount = _serverTree.rootNode->getSubTreeInternalNodeCount();
unsigned long leafNodeCount = ::serverTree.rootNode->getSubTreeLeafNodeCount(); unsigned long leafNodeCount = _serverTree.rootNode->getSubTreeLeafNodeCount();
printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); printf("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
// now set up VoxelPersistThread // now set up VoxelPersistThread
::voxelPersistThread = new VoxelPersistThread(&::serverTree, ::voxelPersistFilename); _voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename);
if (::voxelPersistThread) { if (_voxelPersistThread) {
::voxelPersistThread->initialize(true); _voxelPersistThread->initialize(true);
} }
} }
@ -237,52 +243,52 @@ void VoxelServer::run() {
const char* INPUT_FILE = "-i"; const char* INPUT_FILE = "-i";
const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE); const char* voxelsFilename = getCmdOption(_argc, _argv, INPUT_FILE);
if (voxelsFilename) { if (voxelsFilename) {
serverTree.readFromSVOFile(voxelsFilename); _serverTree.readFromSVOFile(voxelsFilename);
} }
// Check to see if the user passed in a command line option for setting packet send rate // Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond"; const char* PACKETS_PER_SECOND = "--packetsPerSecond";
const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND); const char* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND);
if (packetsPerSecond) { if (packetsPerSecond) {
PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/INTERVALS_PER_SECOND; _packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND;
if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) { if (_packetsPerClientPerInterval < 1) {
PACKETS_PER_CLIENT_PER_INTERVAL = 1; _packetsPerClientPerInterval = 1;
} }
printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL); printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval);
} }
// for now, initialize the environments with fixed values // for now, initialize the environments with fixed values
environmentData[1].setID(1); _environmentData[1].setID(1);
environmentData[1].setGravity(1.0f); _environmentData[1].setGravity(1.0f);
environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE); _environmentData[1].setAtmosphereCenter(glm::vec3(0.5, 0.5, (0.25 - 0.06125)) * (float)TREE_SCALE);
environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE); _environmentData[1].setAtmosphereInnerRadius(0.030625f * TREE_SCALE);
environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f); _environmentData[1].setAtmosphereOuterRadius(0.030625f * TREE_SCALE * 1.05f);
environmentData[2].setID(2); _environmentData[2].setID(2);
environmentData[2].setGravity(1.0f); _environmentData[2].setGravity(1.0f);
environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE); _environmentData[2].setAtmosphereCenter(glm::vec3(0.5f, 0.5f, 0.5f) * (float)TREE_SCALE);
environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE); _environmentData[2].setAtmosphereInnerRadius(0.1875f * TREE_SCALE);
environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f); _environmentData[2].setAtmosphereOuterRadius(0.1875f * TREE_SCALE * 1.05f);
environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue _environmentData[2].setScatteringWavelengths(glm::vec3(0.475f, 0.570f, 0.650f)); // swaps red and blue
sockaddr senderAddress; sockaddr senderAddress;
unsigned char *packetData = new unsigned char[MAX_PACKET_SIZE]; unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
ssize_t packetLength; ssize_t packetLength;
timeval lastDomainServerCheckIn = {}; timeval lastDomainServerCheckIn = {};
// set up our jurisdiction broadcaster... // set up our jurisdiction broadcaster...
::jurisdictionSender = new JurisdictionSender(::jurisdiction); _jurisdictionSender = new JurisdictionSender(_jurisdiction);
if (::jurisdictionSender) { if (_jurisdictionSender) {
::jurisdictionSender->initialize(true); _jurisdictionSender->initialize(true);
} }
// set up our VoxelServerPacketProcessor // set up our VoxelServerPacketProcessor
::voxelServerPacketProcessor = new VoxelServerPacketProcessor(); _voxelServerPacketProcessor = new VoxelServerPacketProcessor(this);
if (::voxelServerPacketProcessor) { if (_voxelServerPacketProcessor) {
::voxelServerPacketProcessor->initialize(true); _voxelServerPacketProcessor->initialize(true);
} }
// loop to send to nodes requesting data // loop to send to nodes requesting data
while (true) { while (true) {
@ -313,46 +319,50 @@ void VoxelServer::run() {
nodeID); nodeID);
NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength); NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength);
VoxelNodeData* nodeData = (VoxelNodeData*) node->getLinkedData();
if (nodeData && !nodeData->isVoxelSendThreadInitalized()) {
nodeData->initializeVoxelSendThread(this);
}
} else if (packetData[0] == PACKET_TYPE_PING) { } else if (packetData[0] == PACKET_TYPE_PING) {
// If the packet is a ping, let processNodeData handle it. // If the packet is a ping, let processNodeData handle it.
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
} else if (packetData[0] == PACKET_TYPE_DOMAIN) { } else if (packetData[0] == PACKET_TYPE_DOMAIN) {
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
} else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) { } else if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
if (::jurisdictionSender) { if (_jurisdictionSender) {
::jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength); _jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength);
} }
} else if (::voxelServerPacketProcessor) { } else if (_voxelServerPacketProcessor) {
::voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); _voxelServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength);
} else { } else {
printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]); printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]);
} }
} }
} }
if (::jurisdiction) { delete _jurisdiction;
delete ::jurisdiction;
}
if (::jurisdictionSender) { if (_jurisdictionSender) {
::jurisdictionSender->terminate(); _jurisdictionSender->terminate();
delete ::jurisdictionSender; delete _jurisdictionSender;
} }
if (::voxelServerPacketProcessor) { if (_voxelServerPacketProcessor) {
::voxelServerPacketProcessor->terminate(); _voxelServerPacketProcessor->terminate();
delete ::voxelServerPacketProcessor; delete _voxelServerPacketProcessor;
} }
if (::voxelPersistThread) { if (_voxelPersistThread) {
::voxelPersistThread->terminate(); _voxelPersistThread->terminate();
delete ::voxelPersistThread; delete _voxelPersistThread;
} }
// tell our NodeList we're done with notifications // tell our NodeList we're done with notifications
nodeList->removeHook(&nodeWatcher); nodeList->removeHook(&_nodeWatcher);
pthread_mutex_destroy(&::treeLock); pthread_mutex_destroy(&_treeLock);
} }

View file

@ -11,33 +11,79 @@
#define __voxel_server__VoxelServer__ #define __voxel_server__VoxelServer__
#include <Assignment.h> #include <Assignment.h>
#include <EnvironmentData.h>
#include "NodeWatcher.h"
#include "VoxelPersistThread.h"
#include "VoxelSendThread.h"
#include "VoxelServerConsts.h"
#include "VoxelServerPacketProcessor.h"
/// Handles assignments of type VoxelServer - sending voxels to various clients. /// Handles assignments of type VoxelServer - sending voxels to various clients.
class VoxelServer : public Assignment { class VoxelServer : public Assignment {
public: public:
VoxelServer(Assignment::Command command, VoxelServer(Assignment::Command command,
Assignment::Location location = Assignment::GlobalLocation); Assignment::Location location = Assignment::GlobalLocation);
VoxelServer(const unsigned char* dataBuffer, int numBytes); VoxelServer(const unsigned char* dataBuffer, int numBytes);
/// runs the voxel server assignment /// runs the voxel server assignment
void run(); void run();
/// allows setting of run arguments /// allows setting of run arguments
static void setArguments(int argc, char** argv); void setArguments(int argc, char** argv);
/// when VoxelServer class is used by voxel-server stand alone executable it calls this to specify the domain /// when VoxelServer class is used by voxel-server stand alone executable it calls this to specify the domain
/// and port it is handling. When called by assignment-client, this is not needed because assignment-client /// and port it is handling. When called by assignment-client, this is not needed because assignment-client
/// handles ports and domains automatically. /// handles ports and domains automatically.
/// \param const char* domain domain name, IP address, or local to specify the domain the voxel server is serving /// \param const char* domain domain name, IP address, or local to specify the domain the voxel server is serving
/// \param int port port the voxel server will listen on /// \param int port port the voxel server will listen on
static void setupDomainAndPort(const char* domain, int port); void setupStandAlone(const char* domain, int port);
bool wantsDebugVoxelSending() const { return _debugVoxelSending; }
bool wantsDebugVoxelReceiving() const { return _debugVoxelReceiving; }
bool wantShowAnimationDebug() const { return _shouldShowAnimationDebug; }
bool wantSendEnvironments() const { return _sendEnvironments; }
bool wantDumpVoxelsOnMove() const { return _dumpVoxelsOnMove; }
bool wantDisplayVoxelStats() const { return _displayVoxelStats; }
VoxelTree& getServerTree() { return _serverTree; }
JurisdictionMap* getJurisdiction() { return _jurisdiction; }
void lockTree() { pthread_mutex_lock(&_treeLock); }
void unlockTree() { pthread_mutex_unlock(&_treeLock); }
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
private: private:
static int _argc; int _argc;
static const char** _argv; const char** _argv;
static bool _dontKillOnMissingDomain; bool _dontKillOnMissingDomain;
char _voxelPersistFilename[MAX_FILENAME_LENGTH];
int _packetsPerClientPerInterval;
VoxelTree _serverTree; // this IS a reaveraging tree
bool _wantVoxelPersist;
bool _wantLocalDomain;
bool _debugVoxelSending;
bool _shouldShowAnimationDebug;
bool _displayVoxelStats;
bool _debugVoxelReceiving;
bool _sendEnvironments;
bool _sendMinimalEnvironment;
bool _dumpVoxelsOnMove;
JurisdictionMap* _jurisdiction;
JurisdictionSender* _jurisdictionSender;
VoxelServerPacketProcessor* _voxelServerPacketProcessor;
VoxelPersistThread* _voxelPersistThread;
pthread_mutex_t _treeLock;
EnvironmentData _environmentData[3];
NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
}; };
#endif // __voxel_server__VoxelServer__ #endif // __voxel_server__VoxelServer__

View file

@ -0,0 +1,31 @@
// VoxelServerConsts.h
// voxel-server
//
// Created by Brad Hefta-Gaub on 8/21/13
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __voxel_server__VoxelServerConsts__
#define __voxel_server__VoxelServerConsts__
#include <SharedUtil.h>
#include <NodeList.h> // for MAX_PACKET_SIZE
#include <JurisdictionSender.h>
#include <VoxelTree.h>
#include "VoxelServerPacketProcessor.h"
const int MAX_FILENAME_LENGTH = 1024;
const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float));
const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES;
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
const int INTERVALS_PER_SECOND = 1000 * 1000 / VOXEL_SEND_INTERVAL_USECS;
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
extern const char* LOCAL_VOXELS_PERSIST_FILE;
extern const char* VOXELS_PERSIST_FILE;
#endif // __voxel_server__VoxelServerConsts__

View file

@ -12,33 +12,39 @@
#include <PerfStat.h> #include <PerfStat.h>
#include "VoxelServer.h" #include "VoxelServer.h"
#include "VoxelServerState.h" #include "VoxelServerConsts.h"
#include "VoxelServerPacketProcessor.h" #include "VoxelServerPacketProcessor.h"
VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) :
_myServer(myServer),
_receivedPacketCount(0) {
}
void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
int numBytesPacketHeader = numBytesForPacketHeader(packetData); int numBytesPacketHeader = numBytesForPacketHeader(packetData);
if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) { if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE); bool destructive = (packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE);
PerformanceWarning warn(::shouldShowAnimationDebug, PerformanceWarning warn(_myServer->wantShowAnimationDebug(),
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
::shouldShowAnimationDebug); _myServer->wantShowAnimationDebug());
::receivedPacketCount++; _receivedPacketCount++;
unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader))); unsigned short int itemNumber = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
if (::shouldShowAnimationDebug) { if (_myServer->wantShowAnimationDebug()) {
printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n", printf("got %s - command from client receivedBytes=%ld itemNumber=%d\n",
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
packetLength, itemNumber); packetLength, itemNumber);
} }
if (::debugVoxelReceiving) { if (_myServer->wantsDebugVoxelReceiving()) {
printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n", printf("got %s - %d command from client receivedBytes=%ld itemNumber=%d\n",
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL", destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
::receivedPacketCount, packetLength, itemNumber); _receivedPacketCount, packetLength, itemNumber);
} }
int atByte = numBytesPacketHeader + sizeof(itemNumber); int atByte = numBytesPacketHeader + sizeof(itemNumber);
unsigned char* voxelData = (unsigned char*)&packetData[atByte]; unsigned char* voxelData = (unsigned char*)&packetData[atByte];
@ -48,7 +54,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES; int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
int voxelCodeSize = bytesRequiredForCodeLength(octets); int voxelCodeSize = bytesRequiredForCodeLength(octets);
if (::shouldShowAnimationDebug) { if (_myServer->wantShowAnimationDebug()) {
int red = voxelData[voxelCodeSize + 0]; int red = voxelData[voxelCodeSize + 0];
int green = voxelData[voxelCodeSize + 1]; int green = voxelData[voxelCodeSize + 1];
int blue = voxelData[voxelCodeSize + 2]; int blue = voxelData[voxelCodeSize + 2];
@ -58,7 +64,7 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
delete[] vertices; delete[] vertices;
} }
serverTree.readCodeColorBufferToTree(voxelData, destructive); _myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
// skip to next // skip to next
voxelData += voxelDataSize; voxelData += voxelDataSize;
atByte += voxelDataSize; atByte += voxelDataSize;
@ -73,9 +79,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
} else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) { } else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
// Send these bits off to the VoxelTree class to process them // Send these bits off to the VoxelTree class to process them
pthread_mutex_lock(&::treeLock); _myServer->lockTree();
::serverTree.processRemoveVoxelBitstream((unsigned char*)packetData, packetLength); _myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength);
pthread_mutex_unlock(&::treeLock); _myServer->unlockTree();
// Make sure our Node and NodeList knows we've heard from this node. // Make sure our Node and NodeList knows we've heard from this node.
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);

View file

@ -12,11 +12,20 @@
#define __voxel_server__VoxelServerPacketProcessor__ #define __voxel_server__VoxelServerPacketProcessor__
#include <ReceivedPacketProcessor.h> #include <ReceivedPacketProcessor.h>
class VoxelServer;
/// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes /// Handles processing of incoming network packets for the voxel-server. As with other ReceivedPacketProcessor classes
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
class VoxelServerPacketProcessor : public ReceivedPacketProcessor { class VoxelServerPacketProcessor : public ReceivedPacketProcessor {
public:
VoxelServerPacketProcessor(VoxelServer* myServer);
protected: protected:
virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
private:
VoxelServer* _myServer;
int _receivedPacketCount;
}; };
#endif // __voxel_server__VoxelServerPacketProcessor__ #endif // __voxel_server__VoxelServerPacketProcessor__

View file

@ -1,53 +0,0 @@
// VoxelServer.h
// voxel-server
//
// Created by Brad Hefta-Gaub on 8/21/13
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
//
#ifndef __voxel_server__VoxelServerState__
#define __voxel_server__VoxelServerState__
#include <SharedUtil.h>
#include <NodeList.h> // for MAX_PACKET_SIZE
#include <JurisdictionSender.h>
#include <VoxelTree.h>
#include "VoxelServerPacketProcessor.h"
const int MAX_FILENAME_LENGTH = 1024;
const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float));
const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES;
const int MIN_BRIGHTNESS = 64;
const float DEATH_STAR_RADIUS = 4.0;
const float MAX_CUBE = 0.05f;
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
const int INTERVALS_PER_SECOND = 1000 * 1000 / VOXEL_SEND_INTERVAL_USECS;
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
extern const char* LOCAL_VOXELS_PERSIST_FILE;
extern const char* VOXELS_PERSIST_FILE;
extern char voxelPersistFilename[MAX_FILENAME_LENGTH];
extern int PACKETS_PER_CLIENT_PER_INTERVAL;
extern VoxelTree serverTree; // this IS a reaveraging tree
extern bool wantVoxelPersist;
extern bool wantLocalDomain;
extern bool debugVoxelSending;
extern bool shouldShowAnimationDebug;
extern bool displayVoxelStats;
extern bool debugVoxelReceiving;
extern bool sendEnvironments;
extern bool sendMinimalEnvironment;
extern bool dumpVoxelsOnMove;
extern int receivedPacketCount;
extern JurisdictionMap* jurisdiction;
extern JurisdictionSender* jurisdictionSender;
extern VoxelServerPacketProcessor* voxelServerPacketProcessor;
extern pthread_mutex_t treeLock;
#endif // __voxel_server__VoxelServerState__

View file

@ -29,19 +29,19 @@ int main(int argc, const char * argv[]) {
} }
printf("portParameter=%s listenPort=%d\n", portParameter, listenPort); printf("portParameter=%s listenPort=%d\n", portParameter, listenPort);
} }
VoxelServer ourVoxelServer(Assignment::CreateCommand);
if (wantLocalDomain) { if (wantLocalDomain) {
VoxelServer::setupDomainAndPort(local, listenPort); ourVoxelServer.setupStandAlone(local, listenPort);
} else { } else {
if (domainIP) { if (domainIP) {
VoxelServer::setupDomainAndPort(domainIP, listenPort); ourVoxelServer.setupStandAlone(domainIP, listenPort);
} }
} }
VoxelServer::setArguments(argc, const_cast<char**>(argv)); ourVoxelServer.setArguments(argc, const_cast<char**>(argv));
ourVoxelServer.run();
VoxelServer dummyAssignedVoxelServer(Assignment::CreateCommand);
dummyAssignedVoxelServer.run();
} }