From bc5317f20bb46c5b02c52c797b6d0220f37c6585 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 4 Dec 2013 12:09:05 -0800 Subject: [PATCH] removed not yet ready for prime time libraries --- .../particle-server/CMakeLists.txt.disabled | 42 - .../src/ParticlePersistThread.cpp | 86 -- .../src/ParticlePersistThread.h | 44 - .../src/ParticleReceiverData.cpp | 276 ------ .../src/ParticleReceiverData.h | 123 --- .../src/ParticleSendThread.cpp | 551 ------------ .../particle-server/src/ParticleSendThread.h | 47 - .../particle-server/src/ParticleServer.cpp | 802 ------------------ .../particle-server/src/ParticleServer.h | 91 -- .../src/ParticleServerConsts.h | 28 - .../src/ParticleServerPacketProcessor.cpp | 222 ----- .../src/ParticleServerPacketProcessor.h | 83 -- libraries/particles/CMakeLists.txt | 28 - libraries/particles/src/ParticleTree.cpp | 1 - 14 files changed, 2424 deletions(-) delete mode 100644 libraries/particle-server/CMakeLists.txt.disabled delete mode 100644 libraries/particle-server/src/ParticlePersistThread.cpp delete mode 100644 libraries/particle-server/src/ParticlePersistThread.h delete mode 100644 libraries/particle-server/src/ParticleReceiverData.cpp delete mode 100644 libraries/particle-server/src/ParticleReceiverData.h delete mode 100644 libraries/particle-server/src/ParticleSendThread.cpp delete mode 100644 libraries/particle-server/src/ParticleSendThread.h delete mode 100644 libraries/particle-server/src/ParticleServer.cpp delete mode 100644 libraries/particle-server/src/ParticleServer.h delete mode 100644 libraries/particle-server/src/ParticleServerConsts.h delete mode 100644 libraries/particle-server/src/ParticleServerPacketProcessor.cpp delete mode 100644 libraries/particle-server/src/ParticleServerPacketProcessor.h delete mode 100644 libraries/particles/CMakeLists.txt delete mode 100644 libraries/particles/src/ParticleTree.cpp diff --git a/libraries/particle-server/CMakeLists.txt.disabled b/libraries/particle-server/CMakeLists.txt.disabled deleted file mode 100644 index 9a1b7a7223..0000000000 --- a/libraries/particle-server/CMakeLists.txt.disabled +++ /dev/null @@ -1,42 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -set(TARGET_NAME particle-server) - -find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiLibrary.cmake) - -# grab cJSON and civetweb sources to pass as OPTIONAL_SRCS -FILE(GLOB OPTIONAL_SRCS ${ROOT_DIR}/externals/civetweb/src/*) - -setup_hifi_library(${TARGET_NAME} ${OPTIONAL_SRCS}) - -include_directories(${ROOT_DIR}/externals/civetweb/include) - -qt5_use_modules(${TARGET_NAME} Widgets) - -# inluce GLM -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - -# link in the shared library -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -# link ZLIB -find_package(ZLIB) -include_directories(${ZLIB_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES}) - -# link in the hifi octree library -link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) - -# link in the hifi particles library -link_hifi_library(particles ${TARGET_NAME} ${ROOT_DIR}) - diff --git a/libraries/particle-server/src/ParticlePersistThread.cpp b/libraries/particle-server/src/ParticlePersistThread.cpp deleted file mode 100644 index 09e6248de7..0000000000 --- a/libraries/particle-server/src/ParticlePersistThread.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// -// ParticlePersistThread.cpp -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded particle persistence -// - -#include -#include -#include -#include - -#include "ParticlePersistThread.h" -#include "ParticleServer.h" - -ParticlePersistThread::ParticlePersistThread(ParticleTree* tree, const char* filename, int persistInterval) : - _tree(tree), - _filename(filename), - _persistInterval(persistInterval), - _initialLoadComplete(false), - _loadTimeUSecs(0) { -} - -bool ParticlePersistThread::process() { - - if (!_initialLoadComplete) { - uint64_t loadStarted = usecTimestampNow(); - qDebug("loading particles from file: %s...\n", _filename); - - bool persistantFileRead; - - _tree->lockForWrite(); - { - PerformanceWarning warn(true, "Loading Particle File", true); - persistantFileRead = _tree->readFromSVOFile(_filename); - } - _tree->unlock(); - - _loadCompleted = time(0); - uint64_t loadDone = usecTimestampNow(); - _loadTimeUSecs = loadDone - loadStarted; - - _tree->clearDirtyBit(); // the tree is clean since we just loaded it - qDebug("DONE loading particles from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); - - unsigned long nodeCount = ParticleNode::getNodeCount(); - unsigned long internalNodeCount = ParticleNode::getInternalNodeCount(); - unsigned long leafNodeCount = ParticleNode::getLeafNodeCount(); - qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); - - double usecPerGet = (double)ParticleNode::getGetChildAtIndexTime() / (double)ParticleNode::getGetChildAtIndexCalls(); - qDebug("getChildAtIndexCalls=%llu getChildAtIndexTime=%llu perGet=%lf \n", - ParticleNode::getGetChildAtIndexTime(), ParticleNode::getGetChildAtIndexCalls(), usecPerGet); - - double usecPerSet = (double)ParticleNode::getSetChildAtIndexTime() / (double)ParticleNode::getSetChildAtIndexCalls(); - qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n", - ParticleNode::getSetChildAtIndexTime(), ParticleNode::getSetChildAtIndexCalls(), usecPerSet); - - _initialLoadComplete = true; - _lastCheck = usecTimestampNow(); // we just loaded, no need to save again - } - - if (isStillRunning()) { - uint64_t MSECS_TO_USECS = 1000; - uint64_t USECS_TO_SLEEP = 100 * MSECS_TO_USECS; // every 100ms - usleep(USECS_TO_SLEEP); - uint64_t now = usecTimestampNow(); - uint64_t sinceLastSave = now - _lastCheck; - uint64_t intervalToCheck = _persistInterval * MSECS_TO_USECS; - - if (sinceLastSave > intervalToCheck) { - // check the dirty bit and persist here... - _lastCheck = usecTimestampNow(); - if (_tree->isDirty()) { - qDebug("saving particles to file %s...\n",_filename); - _tree->writeToSVOFile(_filename); - _tree->clearDirtyBit(); // tree is clean after saving - qDebug("DONE saving particles to file...\n"); - } - } - } - return isStillRunning(); // keep running till they terminate us -} diff --git a/libraries/particle-server/src/ParticlePersistThread.h b/libraries/particle-server/src/ParticlePersistThread.h deleted file mode 100644 index 0d1e12f56c..0000000000 --- a/libraries/particle-server/src/ParticlePersistThread.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// ParticlePersistThread.h -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded particle persistence -// - -#ifndef __particle_server__ParticlePersistThread__ -#define __particle_server__ParticlePersistThread__ - -#include -#include -#include - -/// Generalized threaded processor for handling received inbound packets. -class ParticlePersistThread : public virtual GenericThread { -public: - static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds - - ParticlePersistThread(ParticleTree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL); - - bool isInitialLoadComplete() const { return _initialLoadComplete; } - - time_t* getLoadCompleted() { return &_loadCompleted; } - uint64_t getLoadElapsedTime() const { return _loadTimeUSecs; } - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); -private: - ParticleTree* _tree; - const char* _filename; - int _persistInterval; - bool _initialLoadComplete; - - time_t _loadCompleted; - uint64_t _loadTimeUSecs; - uint64_t _lastCheck; -}; - -#endif // __particle_server__ParticlePersistThread__ diff --git a/libraries/particle-server/src/ParticleReceiverData.cpp b/libraries/particle-server/src/ParticleReceiverData.cpp deleted file mode 100644 index 0c0390c5f3..0000000000 --- a/libraries/particle-server/src/ParticleReceiverData.cpp +++ /dev/null @@ -1,276 +0,0 @@ -// -// ParticleReceiverData.cpp -// hifi -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "PacketHeaders.h" -#include "SharedUtil.h" -#include "ParticleReceiverData.h" -#include -#include -#include "ParticleSendThread.h" - -ParticleReceiverData::ParticleReceiverData(Node* owningNode) : - ParticleQuery(owningNode), - _viewSent(false), - _particlePacketAvailableBytes(MAX_PACKET_SIZE), - _maxSearchLevel(1), - _maxLevelReachedInLastSearch(1), - _lastTimeBagEmpty(0), - _viewFrustumChanging(false), - _viewFrustumJustStoppedChanging(true), - _currentPacketIsColor(true), - _currentPacketIsCompressed(false), - _particleSendThread(NULL), - _lastClientBoundaryLevelAdjust(0), - _lastClientParticleSizeScale(DEFAULT_PARTICLE_SIZE_SCALE), - _lodChanged(false), - _lodInitialized(false) -{ - _particlePacket = new unsigned char[MAX_PACKET_SIZE]; - _particlePacketAt = _particlePacket; - _lastParticlePacket = new unsigned char[MAX_PACKET_SIZE]; - _lastParticlePacketLength = 0; - _duplicatePacketCount = 0; - _sequenceNumber = 0; - resetParticlePacket(true); // don't bump sequence -} - -void ParticleReceiverData::initializeParticleSendThread(ParticleServer* particleServer) { - // Create particle sending thread... - QUuid nodeUUID = getOwningNode()->getUUID(); - _particleSendThread = new ParticleSendThread(nodeUUID, particleServer); - _particleSendThread->initialize(true); -} - -bool ParticleReceiverData::packetIsDuplicate() const { - // since our packets now include header information, like sequence number, and createTime, we can't just do a memcmp - // of the entire packet, we need to compare only the packet content... - if (_lastParticlePacketLength == getPacketLength()) { - return memcmp(_lastParticlePacket + PARTICLE_PACKET_HEADER_SIZE, - _particlePacket+PARTICLE_PACKET_HEADER_SIZE , getPacketLength() - PARTICLE_PACKET_HEADER_SIZE) == 0; - } - return false; -} - -bool ParticleReceiverData::shouldSuppressDuplicatePacket() { - bool shouldSuppress = false; // assume we won't suppress - - // only consider duplicate packets - if (packetIsDuplicate()) { - _duplicatePacketCount++; - - // If this is the first suppressed packet, remember our time... - if (_duplicatePacketCount == 1) { - _firstSuppressedPacket = usecTimestampNow(); - } - - // How long has it been since we've sent one, if we're still under our max time, then keep considering - // this packet for suppression - uint64_t now = usecTimestampNow(); - long sinceFirstSuppressedPacket = now - _firstSuppressedPacket; - const long MAX_TIME_BETWEEN_DUPLICATE_PACKETS = 1000 * 1000; // 1 second. - - if (sinceFirstSuppressedPacket < MAX_TIME_BETWEEN_DUPLICATE_PACKETS) { - // Finally, if we know we've sent at least one duplicate out, then suppress the rest... - if (_duplicatePacketCount >= 1) { - shouldSuppress = true; - } - } else { - // Reset our count, we've reached our maximum time. - _duplicatePacketCount = 0; - } - } else { - // Reset our count, it wasn't a duplicate - _duplicatePacketCount = 0; - } - return shouldSuppress; -} - -void ParticleReceiverData::resetParticlePacket(bool lastWasSurpressed) { - // Whenever we call this, we will keep a copy of the last packet, so we can determine if the last packet has - // changed since we last reset it. Since we know that no two packets can ever be identical without being the same - // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing - // packet send rate. - _lastParticlePacketLength = getPacketLength(); - memcpy(_lastParticlePacket, _particlePacket, _lastParticlePacketLength); - - // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use - // the clients requested color state. - _currentPacketIsColor = getWantColor(); - _currentPacketIsCompressed = getWantCompression(); - PARTICLE_PACKET_FLAGS flags = 0; - if (_currentPacketIsColor) { - setAtBit(flags,PACKET_IS_COLOR_BIT); - } - if (_currentPacketIsCompressed) { - setAtBit(flags,PACKET_IS_COMPRESSED_BIT); - } - - _particlePacketAvailableBytes = MAX_PACKET_SIZE; - int numBytesPacketHeader = populateTypeAndVersion(_particlePacket, PACKET_TYPE_PARTICLE_DATA); - _particlePacketAt = _particlePacket + numBytesPacketHeader; - _particlePacketAvailableBytes -= numBytesPacketHeader; - - // pack in flags - PARTICLE_PACKET_FLAGS* flagsAt = (PARTICLE_PACKET_FLAGS*)_particlePacketAt; - *flagsAt = flags; - _particlePacketAt += sizeof(PARTICLE_PACKET_FLAGS); - _particlePacketAvailableBytes -= sizeof(PARTICLE_PACKET_FLAGS); - - // pack in sequence number - PARTICLE_PACKET_SEQUENCE* sequenceAt = (PARTICLE_PACKET_SEQUENCE*)_particlePacketAt; - *sequenceAt = _sequenceNumber; - _particlePacketAt += sizeof(PARTICLE_PACKET_SEQUENCE); - _particlePacketAvailableBytes -= sizeof(PARTICLE_PACKET_SEQUENCE); - if (!(lastWasSurpressed || _lastParticlePacketLength == PARTICLE_PACKET_HEADER_SIZE)) { - _sequenceNumber++; - } - - // pack in timestamp - PARTICLE_PACKET_SENT_TIME now = usecTimestampNow(); - PARTICLE_PACKET_SENT_TIME* timeAt = (PARTICLE_PACKET_SENT_TIME*)_particlePacketAt; - *timeAt = now; - _particlePacketAt += sizeof(PARTICLE_PACKET_SENT_TIME); - _particlePacketAvailableBytes -= sizeof(PARTICLE_PACKET_SENT_TIME); - - _particlePacketWaiting = false; -} - -void ParticleReceiverData::writeToPacket(const unsigned char* buffer, int bytes) { - // compressed packets include lead bytes which contain compressed size, this allows packing of - // multiple compressed portions together - if (_currentPacketIsCompressed) { - *(PARTICLE_PACKET_INTERNAL_SECTION_SIZE*)_particlePacketAt = bytes; - _particlePacketAt += sizeof(PARTICLE_PACKET_INTERNAL_SECTION_SIZE); - _particlePacketAvailableBytes -= sizeof(PARTICLE_PACKET_INTERNAL_SECTION_SIZE); - } - if (bytes <= _particlePacketAvailableBytes) { - memcpy(_particlePacketAt, buffer, bytes); - _particlePacketAvailableBytes -= bytes; - _particlePacketAt += bytes; - _particlePacketWaiting = true; - } -} - -ParticleReceiverData::~ParticleReceiverData() { - delete[] _particlePacket; - delete[] _lastParticlePacket; - - if (_particleSendThread) { - _particleSendThread->terminate(); - delete _particleSendThread; - } -} - -bool ParticleReceiverData::updateCurrentViewFrustum() { - bool currentViewFrustumChanged = false; - ViewFrustum newestViewFrustum; - // get position and orientation details from the camera - newestViewFrustum.setPosition(getCameraPosition()); - newestViewFrustum.setOrientation(getCameraOrientation()); - - // Also make sure it's got the correct lens details from the camera - float originalFOV = getCameraFov(); - float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; - - newestViewFrustum.setFieldOfView(wideFOV); // hack - newestViewFrustum.setAspectRatio(getCameraAspectRatio()); - newestViewFrustum.setNearClip(getCameraNearClip()); - newestViewFrustum.setFarClip(getCameraFarClip()); - newestViewFrustum.setEyeOffsetPosition(getCameraEyeOffsetPosition()); - - // if there has been a change, then recalculate - if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) { - _currentViewFrustum = newestViewFrustum; - _currentViewFrustum.calculate(); - currentViewFrustumChanged = true; - } - - // Also check for LOD changes from the client - if (_lodInitialized) { - if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { - _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); - _lodChanged = true; - } - if (_lastClientParticleSizeScale != getParticleSizeScale()) { - _lastClientParticleSizeScale = getParticleSizeScale(); - _lodChanged = true; - } - } else { - _lodInitialized = true; - _lastClientParticleSizeScale = getParticleSizeScale(); - _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); - _lodChanged = false; - } - - // When we first detect that the view stopped changing, we record this. - // but we don't change it back to false until we've completely sent this - // scene. - if (_viewFrustumChanging && !currentViewFrustumChanged) { - _viewFrustumJustStoppedChanging = true; - } - _viewFrustumChanging = currentViewFrustumChanged; - return currentViewFrustumChanged; -} - -void ParticleReceiverData::setViewSent(bool viewSent) { - _viewSent = viewSent; - if (viewSent) { - _viewFrustumJustStoppedChanging = false; - _lodChanged = false; - } -} - -void ParticleReceiverData::updateLastKnownViewFrustum() { - bool frustumChanges = !_lastKnownViewFrustum.isVerySimilar(_currentViewFrustum); - - if (frustumChanges) { - // save our currentViewFrustum into our lastKnownViewFrustum - _lastKnownViewFrustum = _currentViewFrustum; - } - - // save that we know the view has been sent. - uint64_t now = usecTimestampNow(); - setLastTimeBagEmpty(now); // is this what we want? poor names -} - - -bool ParticleReceiverData::moveShouldDump() const { - glm::vec3 oldPosition = _lastKnownViewFrustum.getPosition(); - glm::vec3 newPosition = _currentViewFrustum.getPosition(); - - // theoretically we could make this slightly larger but relative to avatar scale. - const float MAXIMUM_MOVE_WITHOUT_DUMP = 0.0f; - if (glm::distance(newPosition, oldPosition) > MAXIMUM_MOVE_WITHOUT_DUMP) { - return true; - } - return false; -} - -void ParticleReceiverData::dumpOutOfView() { - int stillInView = 0; - int outOfView = 0; - ParticleNodeBag tempBag; - while (!nodeBag.isEmpty()) { - ParticleNode* node = nodeBag.extract(); - if (node->isInView(_currentViewFrustum)) { - tempBag.insert(node); - stillInView++; - } else { - outOfView++; - } - } - if (stillInView > 0) { - while (!tempBag.isEmpty()) { - ParticleNode* node = tempBag.extract(); - if (node->isInView(_currentViewFrustum)) { - nodeBag.insert(node); - } - } - } -} - diff --git a/libraries/particle-server/src/ParticleReceiverData.h b/libraries/particle-server/src/ParticleReceiverData.h deleted file mode 100644 index d9b4eb3e34..0000000000 --- a/libraries/particle-server/src/ParticleReceiverData.h +++ /dev/null @@ -1,123 +0,0 @@ -// -// ParticleReceiverData.h -// hifi -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// - -#ifndef __hifi__ParticleReceiverData__ -#define __hifi__ParticleReceiverData__ - -#include -#include -#include -#include - -#include -#include -#include -#include - -class ParticleSendThread; -class ParticleServer; - -class ParticleReceiverData : public ParticleQuery { -public: - ParticleReceiverData(Node* owningNode); - virtual ~ParticleReceiverData(); - - void resetParticlePacket(bool lastWasSurpressed = false); // resets particle packet to after "V" header - - void writeToPacket(const unsigned char* buffer, int bytes); // writes to end of packet - - const unsigned char* getPacket() const { return _particlePacket; } - int getPacketLength() const { return (MAX_PACKET_SIZE - _particlePacketAvailableBytes); } - bool isPacketWaiting() const { return _particlePacketWaiting; } - - bool packetIsDuplicate() const; - bool shouldSuppressDuplicatePacket(); - - int getAvailable() const { return _particlePacketAvailableBytes; } - int getMaxSearchLevel() const { return _maxSearchLevel; } - void resetMaxSearchLevel() { _maxSearchLevel = 1; } - void incrementMaxSearchLevel() { _maxSearchLevel++; } - - int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; } - void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } - - ParticleNodeBag nodeBag; - CoverageMap map; - - ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } - ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; } - - // These are not classic setters because they are calculating and maintaining state - // which is set asynchronously through the network receive - bool updateCurrentViewFrustum(); - void updateLastKnownViewFrustum(); - - bool getViewSent() const { return _viewSent; } - void setViewSent(bool viewSent); - - bool getViewFrustumChanging() const { return _viewFrustumChanging; } - bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; } - - bool moveShouldDump() const; - - uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; } - void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; } - - bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } - bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); - } - - bool hasLodChanged() const { return _lodChanged; }; - - ParticleSceneStats stats; - - void initializeParticleSendThread(ParticleServer* particleServer); - bool isParticleSendThreadInitalized() { return _particleSendThread; } - - void dumpOutOfView(); - -private: - ParticleReceiverData(const ParticleReceiverData &); - ParticleReceiverData& operator= (const ParticleReceiverData&); - - bool _viewSent; - unsigned char* _particlePacket; - unsigned char* _particlePacketAt; - int _particlePacketAvailableBytes; - bool _particlePacketWaiting; - - unsigned char* _lastParticlePacket; - int _lastParticlePacketLength; - int _duplicatePacketCount; - uint64_t _firstSuppressedPacket; - - int _maxSearchLevel; - int _maxLevelReachedInLastSearch; - ViewFrustum _currentViewFrustum; - ViewFrustum _lastKnownViewFrustum; - uint64_t _lastTimeBagEmpty; - bool _viewFrustumChanging; - bool _viewFrustumJustStoppedChanging; - bool _currentPacketIsColor; - bool _currentPacketIsCompressed; - - ParticleSendThread* _particleSendThread; - - // watch for LOD changes - int _lastClientBoundaryLevelAdjust; - float _lastClientParticleSizeScale; - bool _lodChanged; - bool _lodInitialized; - - PARTICLE_PACKET_SEQUENCE _sequenceNumber; -}; - -#endif /* defined(__hifi__ParticleReceiverData__) */ diff --git a/libraries/particle-server/src/ParticleSendThread.cpp b/libraries/particle-server/src/ParticleSendThread.cpp deleted file mode 100644 index b3a398f8ae..0000000000 --- a/libraries/particle-server/src/ParticleSendThread.cpp +++ /dev/null @@ -1,551 +0,0 @@ -// -// ParticleSendThread.cpp -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded particle packet sender -// - -#include -#include -#include -#include - -#include "ParticleSendThread.h" -#include "ParticleServer.h" -#include "ParticleServerConsts.h" - - -uint64_t startSceneSleepTime = 0; -uint64_t endSceneSleepTime = 0; - - -ParticleSendThread::ParticleSendThread(const QUuid& nodeUUID, ParticleServer* myServer) : - _nodeUUID(nodeUUID), - _myServer(myServer), - _packetData() -{ -} - -bool ParticleSendThread::process() { - uint64_t start = usecTimestampNow(); - bool gotLock = false; - - // don't do any send processing until the initial load of the particles is complete... - if (_myServer->isInitialLoadComplete()) { - Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); - - if (node) { - // make sure the node list doesn't kill our node while we're using it - if (node->trylock()) { - gotLock = true; - ParticleReceiverData* nodeData = NULL; - - nodeData = (ParticleReceiverData*) node->getLinkedData(); - - int packetsSent = 0; - - // Sometimes the node data has not yet been linked, in which case we can't really do anything - if (nodeData) { - bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); - } - packetsSent = deepestLevelParticleDistributor(node, nodeData, viewFrustumChanged); - } - - node->unlock(); // we're done with this node for now. - } - } - } else { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - qDebug("ParticleSendThread::process() waiting for isInitialLoadComplete()\n"); - } - } - - // Only sleep if we're still running and we got the lock last time we tried, otherwise try to get the lock asap - if (isStillRunning() && gotLock) { - // dynamically sleep until we need to fire off the next set of particles - int elapsed = (usecTimestampNow() - start); - int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed; - - if (usecToSleep > 0) { - PerformanceWarning warn(false,"ParticleSendThread... usleep()",false,&_usleepTime,&_usleepCalls); - usleep(usecToSleep); - } else { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - std::cout << "Last send took too much time, not sleeping!\n"; - } - } - } - - return isStillRunning(); // keep running till they terminate us -} - -uint64_t ParticleSendThread::_usleepTime = 0; -uint64_t ParticleSendThread::_usleepCalls = 0; - -uint64_t ParticleSendThread::_totalBytes = 0; -uint64_t ParticleSendThread::_totalWastedBytes = 0; -uint64_t ParticleSendThread::_totalPackets = 0; - -int ParticleSendThread::handlePacketSend(Node* node, ParticleReceiverData* nodeData, int& trueBytesSent, int& truePacketsSent) { - bool debug = _myServer->wantsDebugParticleSending(); - uint64_t now = usecTimestampNow(); - - bool packetSent = false; // did we send a packet? - int packetsSent = 0; - // Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently - // obscure the packet and not send it. This allows the callers and upper level logic to not need to know about - // this rate control savings. - if (nodeData->shouldSuppressDuplicatePacket()) { - nodeData->resetParticlePacket(true); // we still need to reset it though! - return packetsSent; // without sending... - } - - const unsigned char* messageData = nodeData->getPacket(); - int numBytesPacketHeader = numBytesForPacketHeader(messageData); - const unsigned char* dataAt = messageData + numBytesPacketHeader; - dataAt += sizeof(VOXEL_PACKET_FLAGS); - VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); - dataAt += sizeof(VOXEL_PACKET_SEQUENCE); - - - // If we've got a stats message ready to send, then see if we can piggyback them together - if (nodeData->stats.isReadyToSend()) { - // Send the stats message to the client - unsigned char* statsMessage = nodeData->stats.getStatsMessage(); - int statsMessageLength = nodeData->stats.getStatsMessageLength(); - - // If the size of the stats message and the particle message will fit in a packet, then piggyback them - if (nodeData->getPacketLength() + statsMessageLength < MAX_PACKET_SIZE) { - - // copy particle message to back of stats message - memcpy(statsMessage + statsMessageLength, nodeData->getPacket(), nodeData->getPacketLength()); - statsMessageLength += nodeData->getPacketLength(); - - // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since - // there was nothing else to send. - int thisWastedBytes = 0; - _totalWastedBytes += thisWastedBytes; - _totalBytes += nodeData->getPacketLength(); - _totalPackets++; - if (debug) { - qDebug("Adding stats to packet at %llu [%llu]: sequence: %d size:%d [%llu] wasted bytes:%d [%llu]\n", - now, - _totalPackets, - sequence, nodeData->getPacketLength(), _totalBytes, - thisWastedBytes, _totalWastedBytes); - } - - // actually send it - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); - packetSent = true; - } else { - // not enough room in the packet, send two packets - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); - - // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since - // there was nothing else to send. - int thisWastedBytes = 0; - _totalWastedBytes += thisWastedBytes; - _totalBytes += statsMessageLength; - _totalPackets++; - if (debug) { - qDebug("Sending separate stats packet at %llu [%llu]: size:%d [%llu] wasted bytes:%d [%llu]\n", - now, - _totalPackets, - statsMessageLength, _totalBytes, - thisWastedBytes, _totalWastedBytes); - } - - trueBytesSent += statsMessageLength; - truePacketsSent++; - packetsSent++; - - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); - - packetSent = true; - - thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); - _totalWastedBytes += thisWastedBytes; - _totalBytes += nodeData->getPacketLength(); - _totalPackets++; - if (debug) { - qDebug("Sending packet at %llu [%llu]: sequence: %d size:%d [%llu] wasted bytes:%d [%llu]\n", - now, - _totalPackets, - sequence, nodeData->getPacketLength(), _totalBytes, - thisWastedBytes, _totalWastedBytes); - } - } - nodeData->stats.markAsSent(); - } else { - // If there's actually a packet waiting, then send it. - if (nodeData->isPacketWaiting()) { - // just send the particle packet - NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), - nodeData->getPacket(), nodeData->getPacketLength()); - packetSent = true; - - int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength(); - _totalWastedBytes += thisWastedBytes; - _totalBytes += nodeData->getPacketLength(); - _totalPackets++; - if (debug) { - qDebug("Sending packet at %llu [%llu]: sequence:%d size:%d [%llu] wasted bytes:%d [%llu]\n", - now, - _totalPackets, - sequence, nodeData->getPacketLength(), _totalBytes, - thisWastedBytes, _totalWastedBytes); - } - } - } - // remember to track our stats - if (packetSent) { - nodeData->stats.packetSent(nodeData->getPacketLength()); - trueBytesSent += nodeData->getPacketLength(); - truePacketsSent++; - packetsSent++; - nodeData->resetParticlePacket(); - } - - return packetsSent; -} - -/// Version of particle distributor that sends the deepest LOD level at once -int ParticleSendThread::deepestLevelParticleDistributor(Node* node, ParticleReceiverData* nodeData, bool viewFrustumChanged) { - - int truePacketsSent = 0; - int trueBytesSent = 0; - int packetsSentThisInterval = 0; - bool somethingToSend = true; // assume we have something - - // FOR NOW... node tells us if it wants to receive only view frustum deltas - bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); - - // If our packet already has content in it, then we must use the color choice of the waiting packet. - // If we're starting a fresh packet, then... - // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use - // the clients requested color state. - bool wantColor = nodeData->getWantColor(); - bool wantCompression = nodeData->getWantCompression(); - - // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color - // then let's just send that waiting packet. - if (!nodeData->getCurrentPacketFormatMatches()) { - if (nodeData->isPacketWaiting()) { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor=%s wantCompression=%s SENDING PARTIAL PACKET! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - } else { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor=%s wantCompression=%s FIXING HEADER! currentPacketIsColor=%s currentPacketIsCompressed=%s\n", - debug::valueOf(wantColor), debug::valueOf(wantCompression), - debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(nodeData->getCurrentPacketIsCompressed()) ); - } - nodeData->resetParticlePacket(); - } - int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); - } - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, - debug::valueOf(wantCompression), targetSize); - } - - _packetData.changeSettings(wantCompression, targetSize); - } - - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("wantColor/isColor=%s/%s wantCompression/isCompressed=%s/%s viewFrustumChanged=%s, getWantLowResMoving()=%s\n", - debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()), - debug::valueOf(wantCompression), debug::valueOf(nodeData->getCurrentPacketIsCompressed()), - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving())); - } - - const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; - - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("deepestLevelParticleDistributor() viewFrustumChanged=%s, nodeBag.isEmpty=%s, viewSent=%s\n", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty()), - debug::valueOf(nodeData->getViewSent()) - ); - } - - // If the current view frustum has changed OR we have nothing to send, then search against - // the current view frustum for things to send. - if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { - uint64_t now = usecTimestampNow(); - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", - debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); - if (nodeData->getLastTimeBagEmpty() > 0) { - float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f; - if (viewFrustumChanged) { - printf("viewFrustumChanged resetting after elapsed time to send scene = %f seconds", elapsedSceneSend); - } else { - printf("elapsed time to send scene = %f seconds", elapsedSceneSend); - } - printf(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n", - debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), - debug::valueOf(wantColor)); - } - } - - // if our view has changed, we need to reset these things... - if (viewFrustumChanged) { - if (_myServer->wantDumpParticlesOnMove() || nodeData->moveShouldDump() || nodeData->hasLodChanged()) { - nodeData->dumpOutOfView(); - } - nodeData->map.erase(); - } - - if (!viewFrustumChanged && !nodeData->getWantDelta()) { - // only set our last sent time if we weren't resetting due to frustum change - uint64_t now = usecTimestampNow(); - nodeData->setLastTimeBagEmpty(now); - } - - // track completed scenes and send out the stats packet accordingly - nodeData->stats.sceneCompleted(); - ::endSceneSleepTime = _usleepTime; - unsigned long sleepTime = ::endSceneSleepTime - ::startSceneSleepTime; - - unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); - unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - - if (_myServer->wantsDebugParticleSending()) { - qDebug("Scene completed at %llu encodeTime:%lu sleepTime:%lu elapsed:%lu Packets:%llu Bytes:%llu Wasted:%llu\n", - usecTimestampNow(), encodeTime, sleepTime, elapsedTime, _totalPackets, _totalBytes, _totalWastedBytes); - } - - if (_myServer->wantDisplayParticleStats()) { - nodeData->stats.printDebugDetails(); - } - - // start tracking our stats - bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) - && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); - - // If we're starting a full scene, then definitely we want to empty the nodeBag - if (isFullScene) { - nodeData->nodeBag.deleteAll(); - } - - if (_myServer->wantsDebugParticleSending()) { - qDebug("Scene started at %llu Packets:%llu Bytes:%llu Wasted:%llu\n", - usecTimestampNow(),_totalPackets,_totalBytes,_totalWastedBytes); - } - - ::startSceneSleepTime = _usleepTime; - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, - _myServer->getServerTree().rootNode, _myServer->getJurisdiction()); - - // This is the start of "resending" the scene. - bool dontRestartSceneOnMove = false; // this is experimental - if (dontRestartSceneOnMove) { - if (nodeData->nodeBag.isEmpty()) { - nodeData->nodeBag.insert(_myServer->getServerTree().rootNode); // only in case of empty - } - } else { - nodeData->nodeBag.insert(_myServer->getServerTree().rootNode); // original behavior, reset on move or empty - } - } - - // If we have something in our nodeBag, then turn them into packets and send them out... - if (!nodeData->nodeBag.isEmpty()) { - int bytesWritten = 0; - uint64_t start = usecTimestampNow(); - uint64_t startCompressTimeMsecs = ParticlePacketData::getCompressContentTime() / 1000; - uint64_t startCompressCalls = ParticlePacketData::getCompressContentCalls(); - - int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxParticlePacketsPerSecond() / INTERVALS_PER_SECOND)); - int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); - - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxParticlePacketsPerSecond(), clientMaxPacketsPerInterval); - } - - int extraPackingAttempts = 0; - while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval) { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxParticlePacketsPerSecond(), clientMaxPacketsPerInterval); - } - - bool lastNodeDidntFit = false; // assume each node fits - if (!nodeData->nodeBag.isEmpty()) { - ParticleNode* subTree = nodeData->nodeBag.extract(); - bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); - CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - - float particleSizeScale = nodeData->getParticleSizeScale(); - int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); - - int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() - ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - - - bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && - nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); - - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, - WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, particleSizeScale, - nodeData->getLastTimeBagEmpty(), - isFullScene, &nodeData->stats, _myServer->getJurisdiction()); - - - _myServer->getServerTree().lockForRead(); - nodeData->stats.encodeStarted(); - bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, &_packetData, nodeData->nodeBag, params); - - // if we're trying to fill a full size packet, then we use this logic to determine if we have a DIDNT_FIT case. - if (_packetData.getTargetSize() == MAX_VOXEL_PACKET_DATA_SIZE) { - if (_packetData.hasContent() && bytesWritten == 0 && - params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { - lastNodeDidntFit = true; - } - } else { - // in compressed mode and we are trying to pack more... and we don't care if the _packetData has - // content or not... because in this case even if we were unable to pack any data, we want to drop - // below to our sendNow logic, but we do want to track that we attempted to pack extra - extraPackingAttempts++; - if (bytesWritten == 0 && params.stopReason == EncodeBitstreamParams::DIDNT_FIT) { - lastNodeDidntFit = true; - } - } - - nodeData->stats.encodeStopped(); - _myServer->getServerTree().unlock(); - } else { - // If the bag was empty then we didn't even attempt to encode, and so we know the bytesWritten were 0 - bytesWritten = 0; - somethingToSend = false; // this will cause us to drop out of the loop... - } - - // If the last node didn't fit, but we're in compressed mode, then we actually want to see if we can fit a - // little bit more in this packet. To do this we - - // We only consider sending anything if there is something in the _packetData to send... But - // if bytesWritten == 0 it means either the subTree couldn't fit or we had an empty bag... Both cases - // mean we should send the previous packet contents and reset it. - if (lastNodeDidntFit) { - if (_packetData.hasContent()) { - // if for some reason the finalized size is greater than our available size, then probably the "compressed" - // form actually inflated beyond our padding, and in this case we will send the current packet, then - // write to out new packet... - int writtenSize = _packetData.getFinalizedSize() - + (nodeData->getCurrentPacketIsCompressed() ? sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) : 0); - - - if (writtenSize > nodeData->getAvailable()) { - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("writtenSize[%d] > available[%d] too big, sending packet as is.\n", - writtenSize, nodeData->getAvailable()); - } - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - } - - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("calling writeToPacket() available=%d compressedSize=%d uncompressedSize=%d target=%d\n", - nodeData->getAvailable(), _packetData.getFinalizedSize(), - _packetData.getUncompressedSize(), _packetData.getTargetSize()); - } - nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); - extraPackingAttempts = 0; - } - - // If we're not running compressed, the we know we can just send now. Or if we're running compressed, but - // the packet doesn't have enough space to bother attempting to pack more... - bool sendNow = true; - - if (nodeData->getCurrentPacketIsCompressed() && - nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && - extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) { - sendNow = false; // try to pack more - } - - int targetSize = MAX_VOXEL_PACKET_DATA_SIZE; - if (sendNow) { - packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); - } - } else { - // If we're in compressed mode, then we want to see if we have room for more in this wire packet. - // but we've finalized the _packetData, so we want to start a new section, we will do that by - // resetting the packet settings with the max uncompressed size of our current available space - // in the wire packet. We also include room for our section header, and a little bit of padding - // to account for the fact that whenc compressing small amounts of data, we sometimes end up with - // a larger compressed size then uncompressed size - targetSize = nodeData->getAvailable() - sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; - } - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("line:%d _packetData.changeSettings() wantCompression=%s targetSize=%d\n",__LINE__, - debug::valueOf(nodeData->getWantCompression()), targetSize); - } - _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset - } - } - - uint64_t end = usecTimestampNow(); - int elapsedmsec = (end - start)/1000; - - uint64_t endCompressCalls = ParticlePacketData::getCompressContentCalls(); - int elapsedCompressCalls = endCompressCalls - startCompressCalls; - - uint64_t endCompressTimeMsecs = ParticlePacketData::getCompressContentTime() / 1000; - int elapsedCompressTimeMsecs = endCompressTimeMsecs - startCompressTimeMsecs; - - - if (elapsedmsec > 100) { - if (elapsedmsec > 1000) { - int elapsedsec = (end - start)/1000000; - printf("WARNING! packetLoop() took %d seconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets %d nodes still to send\n", - elapsedsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } else { - printf("WARNING! packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - } else if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("packetLoop() took %d milliseconds [%d milliseconds %d calls in compress] to generate %d bytes in %d packets, %d nodes still to send\n", - elapsedmsec, elapsedCompressTimeMsecs, elapsedCompressCalls, trueBytesSent, truePacketsSent, nodeData->nodeBag.count()); - } - - // if after sending packets we've emptied our bag, then we want to remember that we've sent all - // the particles from the current view frustum - if (nodeData->nodeBag.isEmpty()) { - nodeData->updateLastKnownViewFrustum(); - nodeData->setViewSent(true); - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - nodeData->map.printStats(); - } - nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes - } - - if (_myServer->wantsDebugParticleSending() && _myServer->wantsVerboseDebug()) { - printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", - truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), - nodeData->getMaxParticlePacketsPerSecond(), clientMaxPacketsPerInterval); - } - - } // end if bag wasn't empty, and so we sent stuff... - - return truePacketsSent; -} - diff --git a/libraries/particle-server/src/ParticleSendThread.h b/libraries/particle-server/src/ParticleSendThread.h deleted file mode 100644 index c57b4c005b..0000000000 --- a/libraries/particle-server/src/ParticleSendThread.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// ParticleSendThread.h -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded object for sending particles to a client -// - -#ifndef __particle_server__ParticleSendThread__ -#define __particle_server__ParticleSendThread__ - -#include -#include -#include -#include -#include "ParticleReceiverData.h" -#include "ParticleServer.h" - -/// Threaded processor for sending particle packets to a single client -class ParticleSendThread : public virtual GenericThread { -public: - ParticleSendThread(const QUuid& nodeUUID, ParticleServer* myServer); - - static uint64_t _totalBytes; - static uint64_t _totalWastedBytes; - static uint64_t _totalPackets; - - static uint64_t _usleepTime; - static uint64_t _usleepCalls; - -protected: - /// Implements generic processing behavior for this thread. - virtual bool process(); - -private: - QUuid _nodeUUID; - ParticleServer* _myServer; - - int handlePacketSend(Node* node, ParticleReceiverData* nodeData, int& trueBytesSent, int& truePacketsSent); - int deepestLevelParticleDistributor(Node* node, ParticleReceiverData* nodeData, bool viewFrustumChanged); - - ParticlePacketData _packetData; -}; - -#endif // __particle_server__ParticleSendThread__ diff --git a/libraries/particle-server/src/ParticleServer.cpp b/libraries/particle-server/src/ParticleServer.cpp deleted file mode 100644 index 062074fe86..0000000000 --- a/libraries/particle-server/src/ParticleServer.cpp +++ /dev/null @@ -1,802 +0,0 @@ -// -// ParticleSever.cpp -// hifi -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -//#include -#include "ParticleReceiverData.h" -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include "Syssocket.h" -#include "Systime.h" -#else -#include -#include -#include -#endif - -#include "ParticleSever.h" -#include "ParticleSeverConsts.h" - -const char* LOCAL_PARTICLES_PERSIST_FILE = "resources/particles.svo"; -const char* PARTICLES_PERSIST_FILE = "/etc/highfidelity/particle-server/resources/particles.svo"; - -void attachParticleReceiverDataToNode(Node* newNode) { - if (newNode->getLinkedData() == NULL) { - ParticleReceiverData* particleNodeData = new ParticleReceiverData(newNode); - newNode->setLinkedData(particleNodeData); - } -} - -ParticleSever* ParticleSever::_theInstance = NULL; - -ParticleSever::ParticleSever(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), - _serverTree(true) { - _argc = 0; - _argv = NULL; - - _packetsPerClientPerInterval = 10; - _wantParticlePersist = true; - _wantLocalDomain = false; - _debugParticleSending = false; - _shouldShowAnimationDebug = false; - _displayParticleStats = false; - _debugParticleReceiving = false; - _sendEnvironments = true; - _sendMinimalEnvironment = false; - _dumpParticlesOnMove = false; - _verboseDebug = false; - _jurisdiction = NULL; - _jurisdictionSender = NULL; - _ParticleSeverPacketProcessor = NULL; - _particlePersistThread = NULL; - _parsedArgV = NULL; - - _started = time(0); - _startedUSecs = usecTimestampNow(); - - _theInstance = this; -} - -ParticleSever::~ParticleSever() { - if (_parsedArgV) { - for (int i = 0; i < _argc; i++) { - delete[] _parsedArgV[i]; - } - delete[] _parsedArgV; - } -} - -void ParticleSever::initMongoose(int port) { - // setup the mongoose web server - struct mg_callbacks callbacks = {}; - - QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); - QString listenPort = QString("%1").arg(port); - - - // list of options. Last element must be NULL. - const char* options[] = { - "listening_ports", listenPort.toLocal8Bit().constData(), - "document_root", documentRoot.toLocal8Bit().constData(), - NULL }; - - callbacks.begin_request = civetwebRequestHandler; - - // Start the web server. - mg_start(&callbacks, NULL, options); -} - -int ParticleSever::civetwebRequestHandler(struct mg_connection* connection) { - const struct mg_request_info* ri = mg_get_request_info(connection); - - ParticleSever* theServer = GetInstance(); - -#ifdef FORCE_CRASH - if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) { - qDebug() << "About to force a crash!\n"; - int foo; - int* forceCrash = &foo; - mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n"); - mg_printf(connection, "%s", "forcing a crash....\r\n"); - delete[] forceCrash; - mg_printf(connection, "%s", "did it crash....\r\n"); - return 1; - } -#endif - - bool showStats = false; - if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) { - showStats = true; - } - - if (strcmp(ri->uri, "/resetStats") == 0 && strcmp(ri->request_method, "GET") == 0) { - theServer->_ParticleSeverPacketProcessor->resetStats(); - showStats = true; - } - - if (showStats) { - uint64_t checkSum; - // return a 200 - mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n"); - mg_printf(connection, "%s", "Content-Type: text/html\r\n\r\n"); - mg_printf(connection, "%s", "\r\n"); - mg_printf(connection, "%s", "
\r\n");
-        mg_printf(connection, "%s", "Your Particle Server is running... [RELOAD]\r\n");
-
-        tm* localtm = localtime(&theServer->_started);
-        const int MAX_TIME_LENGTH = 128;
-        char buffer[MAX_TIME_LENGTH];
-        strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm);
-        mg_printf(connection, "Running since: %s", buffer);
-
-        // Convert now to tm struct for UTC
-        tm* gmtm = gmtime(&theServer->_started);
-        if (gmtm != NULL) {
-            strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", gmtm);
-            mg_printf(connection, " [%s UTM] ", buffer);
-        }
-        mg_printf(connection, "%s", "\r\n");
-
-        uint64_t now  = usecTimestampNow();
-        const int USECS_PER_MSEC = 1000;
-        uint64_t msecsElapsed = (now - theServer->_startedUSecs) / USECS_PER_MSEC;
-        const int MSECS_PER_SEC = 1000;
-        const int SECS_PER_MIN = 60;
-        const int MIN_PER_HOUR = 60;
-        const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;
-
-        float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
-        int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
-        int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
-
-        mg_printf(connection, "%s", "Uptime: ");
-        if (hours > 0) {
-            mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" );
-        }
-        if (minutes > 0) {
-            mg_printf(connection, "%d minute%s ", minutes, (minutes > 1) ? "s" : "");
-        }
-        if (seconds > 0) {
-            mg_printf(connection, "%.3f seconds ", seconds);
-        }
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "\r\n");
-
-
-        // display particle file load time
-        if (theServer->isInitialLoadComplete()) {
-            time_t* loadCompleted = theServer->getLoadCompleted();
-            if (loadCompleted) {
-                tm* particlesLoadedAtLocal = localtime(loadCompleted);
-                const int MAX_TIME_LENGTH = 128;
-                char buffer[MAX_TIME_LENGTH];
-                strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", particlesLoadedAtLocal);
-                mg_printf(connection, "Particles Loaded At: %s", buffer);
-
-                // Convert now to tm struct for UTC
-                tm* particlesLoadedAtUTM = gmtime(theServer->getLoadCompleted());
-                if (gmtm != NULL) {
-                    strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", particlesLoadedAtUTM);
-                    mg_printf(connection, " [%s UTM] ", buffer);
-                }
-            } else {
-                mg_printf(connection, "%s", "Particle Persist Disabled...\r\n");
-            }
-            mg_printf(connection, "%s", "\r\n");
-
-
-            uint64_t msecsElapsed = theServer->getLoadElapsedTime() / USECS_PER_MSEC;;
-            float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
-            int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
-            int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
-
-            mg_printf(connection, "%s", "Particles Load Took: ");
-            if (hours > 0) {
-                mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" );
-            }
-            if (minutes > 0) {
-                mg_printf(connection, "%d minute%s ", minutes, (minutes > 1) ? "s" : "");
-            }
-            if (seconds >= 0) {
-                mg_printf(connection, "%.3f seconds", seconds);
-            }
-            mg_printf(connection, "%s", "\r\n");
-
-        } else {
-            mg_printf(connection, "%s", "Particles not yet loaded...\r\n");
-        }
-
-        mg_printf(connection, "%s", "\r\n");
-
-        mg_printf(connection, "%s", "\r\n");
-
-        mg_printf(connection, "%s", "Configuration:\r\n");
-
-        for (int i = 1; i < theServer->_argc; i++) {
-            mg_printf(connection, "%s ", theServer->_argv[i]);
-        }
-        mg_printf(connection, "%s", "\r\n"); // one to end the config line
-        mg_printf(connection, "%s", "\r\n"); // two more for spacing
-        mg_printf(connection, "%s", "\r\n");
-
-        // display scene stats
-        unsigned long nodeCount = ParticleNode::getNodeCount();
-        unsigned long internalNodeCount = ParticleNode::getInternalNodeCount();
-        unsigned long leafNodeCount = ParticleNode::getLeafNodeCount();
-        
-        QLocale locale(QLocale::English);
-        const float AS_PERCENT = 100.0;
-        mg_printf(connection, "%s", "Current Nodes in scene:\r\n");
-        mg_printf(connection, "       Total Nodes: %s nodes\r\n",
-                    locale.toString((uint)nodeCount).rightJustified(16, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "    Internal Nodes: %s nodes (%5.2f%%)\r\n",
-            locale.toString((uint)internalNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(),
-            ((float)internalNodeCount / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "        Leaf Nodes: %s nodes (%5.2f%%)\r\n", 
-            locale.toString((uint)leafNodeCount).rightJustified(16, ' ').toLocal8Bit().constData(),
-            ((float)leafNodeCount / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "\r\n");
-
-
-        // display outbound packet stats
-        mg_printf(connection, "%s", "Particle Packet Statistics...\r\n");
-        uint64_t totalOutboundPackets = ParticleSendThread::_totalPackets;
-        uint64_t totalOutboundBytes = ParticleSendThread::_totalBytes;
-        uint64_t totalWastedBytes = ParticleSendThread::_totalWastedBytes;
-        uint64_t totalBytesOfOctalCodes = ParticlePacketData::getTotalBytesOfOctalCodes();
-        uint64_t totalBytesOfBitMasks = ParticlePacketData::getTotalBytesOfBitMasks();
-        uint64_t totalBytesOfColor = ParticlePacketData::getTotalBytesOfColor();
-
-        const int COLUMN_WIDTH = 10;
-        mg_printf(connection, "           Total Outbound Packets: %s packets\r\n",
-            locale.toString((uint)totalOutboundPackets).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "             Total Outbound Bytes: %s bytes\r\n",
-            locale.toString((uint)totalOutboundBytes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "               Total Wasted Bytes: %s bytes\r\n",
-            locale.toString((uint)totalWastedBytes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "            Total OctalCode Bytes: %s bytes (%5.2f%%)\r\n",
-            locale.toString((uint)totalBytesOfOctalCodes).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
-            ((float)totalBytesOfOctalCodes / (float)totalOutboundBytes) * AS_PERCENT);
-        mg_printf(connection, "             Total BitMasks Bytes: %s bytes (%5.2f%%)\r\n",
-            locale.toString((uint)totalBytesOfBitMasks).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
-            ((float)totalBytesOfBitMasks / (float)totalOutboundBytes) * AS_PERCENT);
-        mg_printf(connection, "                Total Color Bytes: %s bytes (%5.2f%%)\r\n",
-            locale.toString((uint)totalBytesOfColor).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData(),
-            ((float)totalBytesOfColor / (float)totalOutboundBytes) * AS_PERCENT);
-
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "\r\n");
-
-        // display inbound packet stats
-        mg_printf(connection, "%s", "Particle Edit Statistics... [RESET]\r\n");
-        uint64_t averageTransitTimePerPacket = theServer->_ParticleSeverPacketProcessor->getAverageTransitTimePerPacket();
-        uint64_t averageProcessTimePerPacket = theServer->_particleServerPacketProcessor->getAverageProcessTimePerPacket();
-        uint64_t averageLockWaitTimePerPacket = theServer->_particleServerPacketProcessor->getAverageLockWaitTimePerPacket();
-        uint64_t averageProcessTimePerParticle = theServer->_particleServerPacketProcessor->getAverageProcessTimePerParticle();
-        uint64_t averageLockWaitTimePerParticle = theServer->_particleServerPacketProcessor->getAverageLockWaitTimePerParticle();
-        uint64_t totalParticlesProcessed = theServer->_particleServerPacketProcessor->getTotalParticlesProcessed();
-        uint64_t totalPacketsProcessed = theServer->_particleServerPacketProcessor->getTotalPacketsProcessed();
-
-        float averageParticlesPerPacket = totalPacketsProcessed == 0 ? 0 : totalParticlesProcessed / totalPacketsProcessed;
-
-        mg_printf(connection, "           Total Inbound Packets: %s packets\r\n",
-            locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "            Total Inbound Particles: %s particles\r\n",
-            locale.toString((uint)totalParticlesProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "   Average Inbound Particles/Packet: %f particles/packet\r\n", averageParticlesPerPacket);
-        mg_printf(connection, "     Average Transit Time/Packet: %s usecs\r\n", 
-            locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "     Average Process Time/Packet: %s usecs\r\n",
-            locale.toString((uint)averageProcessTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "   Average Wait Lock Time/Packet: %s usecs\r\n", 
-            locale.toString((uint)averageLockWaitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "      Average Process Time/Particle: %s usecs\r\n",
-            locale.toString((uint)averageProcessTimePerParticle).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-        mg_printf(connection, "    Average Wait Lock Time/Particle: %s usecs\r\n", 
-            locale.toString((uint)averageLockWaitTimePerParticle).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-
-
-        int senderNumber = 0;
-        NodeToSenderStatsMap& allSenderStats = theServer->_particleServerPacketProcessor->getSingleSenderStats();
-        for (NodeToSenderStatsMapIterator i = allSenderStats.begin(); i != allSenderStats.end(); i++) {
-            senderNumber++;
-            QUuid senderID = i->first;
-            SingleSenderStats& senderStats = i->second;
-
-            mg_printf(connection, "\r\n             Stats for sender %d uuid: %s\r\n", senderNumber, 
-                senderID.toString().toLocal8Bit().constData());
-
-            averageTransitTimePerPacket = senderStats.getAverageTransitTimePerPacket();
-            averageProcessTimePerPacket = senderStats.getAverageProcessTimePerPacket();
-            averageLockWaitTimePerPacket = senderStats.getAverageLockWaitTimePerPacket();
-            averageProcessTimePerParticle = senderStats.getAverageProcessTimePerParticle();
-            averageLockWaitTimePerParticle = senderStats.getAverageLockWaitTimePerParticle();
-            totalParticlesProcessed = senderStats.getTotalParticlesProcessed();
-            totalPacketsProcessed = senderStats.getTotalPacketsProcessed();
-
-            averageParticlesPerPacket = totalPacketsProcessed == 0 ? 0 : totalParticlesProcessed / totalPacketsProcessed;
-
-            mg_printf(connection, "               Total Inbound Packets: %s packets\r\n",
-                locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "                Total Inbound Particles: %s particles\r\n",
-                locale.toString((uint)totalParticlesProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "       Average Inbound Particles/Packet: %f particles/packet\r\n", averageParticlesPerPacket);
-            mg_printf(connection, "         Average Transit Time/Packet: %s usecs\r\n", 
-                locale.toString((uint)averageTransitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "         Average Process Time/Packet: %s usecs\r\n",
-                locale.toString((uint)averageProcessTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "       Average Wait Lock Time/Packet: %s usecs\r\n", 
-                locale.toString((uint)averageLockWaitTimePerPacket).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "          Average Process Time/Particle: %s usecs\r\n",
-                locale.toString((uint)averageProcessTimePerParticle).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-            mg_printf(connection, "        Average Wait Lock Time/Particle: %s usecs\r\n", 
-                locale.toString((uint)averageLockWaitTimePerParticle).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData());
-
-        }
-
-
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "\r\n");
-
-        // display memory usage stats
-        mg_printf(connection, "%s", "Current Memory Usage Statistics\r\n");
-        mg_printf(connection, "\r\nParticleNode size... %ld bytes\r\n", sizeof(ParticleNode));
-        mg_printf(connection, "%s", "\r\n");
-
-        const char* memoryScaleLabel;
-        const float MEGABYTES = 1000000.f;
-        const float GIGABYTES = 1000000000.f;
-        float memoryScale;
-        if (ParticleNode::getTotalMemoryUsage() / MEGABYTES < 1000.0f) {
-            memoryScaleLabel = "MB";
-            memoryScale = MEGABYTES;
-        } else {
-            memoryScaleLabel = "GB";
-            memoryScale = GIGABYTES;
-        }
-
-        mg_printf(connection, "Particle Node Memory Usage:         %8.2f %s\r\n", 
-            ParticleNode::getParticleMemoryUsage() / memoryScale, memoryScaleLabel);
-        mg_printf(connection, "Octcode Memory Usage:            %8.2f %s\r\n", 
-            ParticleNode::getOctcodeMemoryUsage() / memoryScale, memoryScaleLabel);
-        mg_printf(connection, "External Children Memory Usage:  %8.2f %s\r\n", 
-            ParticleNode::getExternalChildrenMemoryUsage() / memoryScale, memoryScaleLabel);
-        mg_printf(connection, "%s", "                                 -----------\r\n");
-        mg_printf(connection, "                         Total:  %8.2f %s\r\n", 
-            ParticleNode::getTotalMemoryUsage() / memoryScale, memoryScaleLabel);
-
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "ParticleNode Children Population Statistics...\r\n");
-        checkSum = 0;
-        for (int i=0; i <= NUMBER_OF_CHILDREN; i++) {
-            checkSum += ParticleNode::getChildrenCount(i);
-            mg_printf(connection, "    Nodes with %d children:      %s nodes (%5.2f%%)\r\n", i, 
-                locale.toString((uint)ParticleNode::getChildrenCount(i)).rightJustified(16, ' ').toLocal8Bit().constData(),
-                ((float)ParticleNode::getChildrenCount(i) / (float)nodeCount) * AS_PERCENT);
-        }
-        mg_printf(connection, "%s", "                                ----------------------\r\n");
-        mg_printf(connection, "                    Total:      %s nodes\r\n", 
-            locale.toString((uint)checkSum).rightJustified(16, ' ').toLocal8Bit().constData());
-
-#ifdef BLENDED_UNION_CHILDREN
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "ParticleNode Children Encoding Statistics...\r\n");
-        
-        mg_printf(connection, "    Single or No Children:      %10.llu nodes (%5.2f%%)\r\n",
-            ParticleNode::getSingleChildrenCount(), ((float)ParticleNode::getSingleChildrenCount() / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "    Two Children as Offset:     %10.llu nodes (%5.2f%%)\r\n", 
-            ParticleNode::getTwoChildrenOffsetCount(), 
-            ((float)ParticleNode::getTwoChildrenOffsetCount() / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "    Two Children as External:   %10.llu nodes (%5.2f%%)\r\n", 
-            ParticleNode::getTwoChildrenExternalCount(), 
-            ((float)ParticleNode::getTwoChildrenExternalCount() / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "    Three Children as Offset:   %10.llu nodes (%5.2f%%)\r\n", 
-            ParticleNode::getThreeChildrenOffsetCount(), 
-            ((float)ParticleNode::getThreeChildrenOffsetCount() / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "    Three Children as External: %10.llu nodes (%5.2f%%)\r\n", 
-            ParticleNode::getThreeChildrenExternalCount(), 
-            ((float)ParticleNode::getThreeChildrenExternalCount() / (float)nodeCount) * AS_PERCENT);
-        mg_printf(connection, "    Children as External Array: %10.llu nodes (%5.2f%%)\r\n",
-            ParticleNode::getExternalChildrenCount(), 
-            ((float)ParticleNode::getExternalChildrenCount() / (float)nodeCount) * AS_PERCENT);
-
-        checkSum = ParticleNode::getSingleChildrenCount() +
-                            ParticleNode::getTwoChildrenOffsetCount() + ParticleNode::getTwoChildrenExternalCount() + 
-                            ParticleNode::getThreeChildrenOffsetCount() + ParticleNode::getThreeChildrenExternalCount() + 
-                            ParticleNode::getExternalChildrenCount();
-
-        mg_printf(connection, "%s", "                                ----------------\r\n");
-        mg_printf(connection, "                         Total: %10.llu nodes\r\n", checkSum);
-        mg_printf(connection, "                      Expected: %10.lu nodes\r\n", nodeCount);
-
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "In other news....\r\n");
-        mg_printf(connection, "could store 4 children internally:     %10.llu nodes\r\n",
-            ParticleNode::getCouldStoreFourChildrenInternally());
-        mg_printf(connection, "could NOT store 4 children internally: %10.llu nodes\r\n", 
-            ParticleNode::getCouldNotStoreFourChildrenInternally());
-#endif
-
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "\r\n");
-        mg_printf(connection, "%s", "
\r\n"); - - mg_printf(connection, "%s", "
"); - - return 1; - } else { - // have mongoose process this request from the document_root - return 0; - } -} - - -void ParticleSever::setArguments(int argc, char** argv) { - _argc = argc; - _argv = const_cast(argv); - - qDebug("ParticleSever::setArguments()\n"); - for (int i = 0; i < _argc; i++) { - qDebug("_argv[%d]=%s\n", i, _argv[i]); - } - -} - -void ParticleSever::parsePayload() { - - if (getNumPayloadBytes() > 0) { - QString config((const char*) _payload); - - // Now, parse the config - QStringList configList = config.split(" "); - - int argCount = configList.size() + 1; - - qDebug("ParticleSever::parsePayload()... argCount=%d\n",argCount); - - _parsedArgV = new char*[argCount]; - const char* dummy = "config-from-payload"; - _parsedArgV[0] = new char[strlen(dummy) + sizeof(char)]; - strcpy(_parsedArgV[0], dummy); - - for (int i = 1; i < argCount; i++) { - QString configItem = configList.at(i-1); - _parsedArgV[i] = new char[configItem.length() + sizeof(char)]; - strcpy(_parsedArgV[i], configItem.toLocal8Bit().constData()); - qDebug("ParticleSever::parsePayload()... _parsedArgV[%d]=%s\n", i, _parsedArgV[i]); - } - - setArguments(argCount, _parsedArgV); - } -} - -//int main(int argc, const char * argv[]) { -void ParticleSever::run() { - - const char PARTICLE_SERVER_LOGGING_TARGET_NAME[] = "particle-server"; - - // change the logging target name while this is running - Logging::setTargetName(PARTICLE_SERVER_LOGGING_TARGET_NAME); - - // Now would be a good time to parse our arguments, if we got them as assignment - if (getNumPayloadBytes() > 0) { - parsePayload(); - } - - qInstallMessageHandler(Logging::verboseMessageHandler); - - const char* STATUS_PORT = "--statusPort"; - const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); - if (statusPort) { - int statusPortNumber = atoi(statusPort); - initMongoose(statusPortNumber); - } - - - const char* JURISDICTION_FILE = "--jurisdictionFile"; - const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE); - if (jurisdictionFile) { - qDebug("jurisdictionFile=%s\n", jurisdictionFile); - - qDebug("about to readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); - _jurisdiction = new JurisdictionMap(jurisdictionFile); - qDebug("after readFromFile().... jurisdictionFile=%s\n", jurisdictionFile); - } else { - const char* JURISDICTION_ROOT = "--jurisdictionRoot"; - const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT); - if (jurisdictionRoot) { - qDebug("jurisdictionRoot=%s\n", jurisdictionRoot); - } - - const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes"; - const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES); - if (jurisdictionEndNodes) { - qDebug("jurisdictionEndNodes=%s\n", jurisdictionEndNodes); - } - - if (jurisdictionRoot || jurisdictionEndNodes) { - _jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes); - } - } - - // should we send environments? Default is yes, but this command line suppresses sending - const char* DUMP_PARTICLES_ON_MOVE = "--dumpParticlesOnMove"; - _dumpParticlesOnMove = cmdOptionExists(_argc, _argv, DUMP_PARTICLES_ON_MOVE); - qDebug("dumpParticlesOnMove=%s\n", debug::valueOf(_dumpParticlesOnMove)); - - // should we send environments? Default is yes, but this command line suppresses sending - const char* SEND_ENVIRONMENTS = "--sendEnvironments"; - bool dontSendEnvironments = !cmdOptionExists(_argc, _argv, SEND_ENVIRONMENTS); - if (dontSendEnvironments) { - qDebug("Sending environments suppressed...\n"); - _sendEnvironments = false; - } else { - // should we send environments? Default is yes, but this command line suppresses sending - const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment"; - _sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT); - qDebug("Using Minimal Environment=%s\n", debug::valueOf(_sendMinimalEnvironment)); - } - qDebug("Sending environments=%s\n", debug::valueOf(_sendEnvironments)); - - NodeList* nodeList = NodeList::getInstance(); - nodeList->setOwnerType(NODE_TYPE_PARTICLE_SERVER); - - // we need to ask the DS about agents so we can ping/reply with them - const char nodeTypesOfInterest[] = { NODE_TYPE_AGENT, NODE_TYPE_ANIMATION_SERVER}; - nodeList->setNodeTypesOfInterest(nodeTypesOfInterest, sizeof(nodeTypesOfInterest)); - - setvbuf(stdout, NULL, _IOLBF, 0); - - // tell our NodeList about our desire to get notifications - nodeList->addHook(&_nodeWatcher); - nodeList->linkedDataCreateCallback = &attachParticleReceiverDataToNode; - - nodeList->startSilentNodeRemovalThread(); - srand((unsigned)time(0)); - - const char* DISPLAY_PARTICLE_STATS = "--displayParticleStats"; - _displayParticleStats = cmdOptionExists(_argc, _argv, DISPLAY_PARTICLE_STATS); - qDebug("displayParticleStats=%s\n", debug::valueOf(_displayParticleStats)); - - const char* VERBOSE_DEBUG = "--verboseDebug"; - _verboseDebug = cmdOptionExists(_argc, _argv, VERBOSE_DEBUG); - qDebug("verboseDebug=%s\n", debug::valueOf(_verboseDebug)); - - const char* DEBUG_PARTICLE_SENDING = "--debugParticleSending"; - _debugParticleSending = cmdOptionExists(_argc, _argv, DEBUG_PARTICLE_SENDING); - qDebug("debugParticleSending=%s\n", debug::valueOf(_debugParticleSending)); - - const char* DEBUG_PARTICLE_RECEIVING = "--debugParticleReceiving"; - _debugParticleReceiving = cmdOptionExists(_argc, _argv, DEBUG_PARTICLE_RECEIVING); - qDebug("debugParticleReceiving=%s\n", debug::valueOf(_debugParticleReceiving)); - - const char* WANT_ANIMATION_DEBUG = "--shouldShowAnimationDebug"; - _shouldShowAnimationDebug = cmdOptionExists(_argc, _argv, WANT_ANIMATION_DEBUG); - qDebug("shouldShowAnimationDebug=%s\n", debug::valueOf(_shouldShowAnimationDebug)); - - // By default we will particle persist, if you want to disable this, then pass in this parameter - const char* NO_PARTICLE_PERSIST = "--NoParticlePersist"; - if (cmdOptionExists(_argc, _argv, NO_PARTICLE_PERSIST)) { - _wantParticlePersist = false; - } - qDebug("wantParticlePersist=%s\n", debug::valueOf(_wantParticlePersist)); - - // if we want Particle Persistence, set up the local file and persist thread - if (_wantParticlePersist) { - - // Check to see if the user passed in a command line option for setting packet send rate - const char* PARTICLES_PERSIST_FILENAME = "--particlesPersistFilename"; - const char* particlesPersistFilenameParameter = getCmdOption(_argc, _argv, PARTICLES_PERSIST_FILENAME); - if (particlesPersistFilenameParameter) { - strcpy(_particlePersistFilename, particlesPersistFilenameParameter); - } else { - //strcpy(particlePersistFilename, _wantLocalDomain ? LOCAL_PARTICLES_PERSIST_FILE : PARTICLES_PERSIST_FILE); - strcpy(_particlePersistFilename, LOCAL_PARTICLES_PERSIST_FILE); - } - - qDebug("particlePersistFilename=%s\n", _particlePersistFilename); - - // now set up ParticlePersistThread - _particlePersistThread = new ParticlePersistThread(&_serverTree, _particlePersistFilename); - if (_particlePersistThread) { - _particlePersistThread->initialize(true); - } - } - - // Check to see if the user passed in a command line option for loading an old style local - // Particle File. If so, load it now. This is not the same as a particle persist file - const char* INPUT_FILE = "-i"; - const char* particlesFilename = getCmdOption(_argc, _argv, INPUT_FILE); - if (particlesFilename) { - _serverTree.readFromSVOFile(particlesFilename); - } - - // 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* packetsPerSecond = getCmdOption(_argc, _argv, PACKETS_PER_SECOND); - if (packetsPerSecond) { - _packetsPerClientPerInterval = atoi(packetsPerSecond) / INTERVALS_PER_SECOND; - if (_packetsPerClientPerInterval < 1) { - _packetsPerClientPerInterval = 1; - } - qDebug("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, _packetsPerClientPerInterval); - } - - sockaddr senderAddress; - - unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE]; - ssize_t packetLength; - - timeval lastDomainServerCheckIn = {}; - - // set up our jurisdiction broadcaster... - _jurisdictionSender = new JurisdictionSender(_jurisdiction); - if (_jurisdictionSender) { - _jurisdictionSender->initialize(true); - } - - // set up our ParticleSeverPacketProcessor - _particleServerPacketProcessor = new ParticleSeverPacketProcessor(this); - if (_particleServerPacketProcessor) { - _particleServerPacketProcessor->initialize(true); - } - - // Convert now to tm struct for local timezone - tm* localtm = localtime(&_started); - const int MAX_TIME_LENGTH = 128; - char localBuffer[MAX_TIME_LENGTH] = { 0 }; - char utcBuffer[MAX_TIME_LENGTH] = { 0 }; - strftime(localBuffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm); - // Convert now to tm struct for UTC - tm* gmtm = gmtime(&_started); - if (gmtm != NULL) { - strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm); - } - qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n"; - - - // loop to send to nodes requesting data - while (true) { - // check for >= in case one gets past the goalie - if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS) { - qDebug() << "Exit loop... getInstance()->getNumNoReplyDomainCheckIns() >= MAX_SILENT_DOMAIN_SERVER_CHECK_INS\n"; - break; - } - - // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed - if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { - gettimeofday(&lastDomainServerCheckIn, NULL); - NodeList::getInstance()->sendDomainServerCheckIn(); - } - - // ping our inactive nodes to punch holes with them - nodeList->possiblyPingInactiveNodes(); - - if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) && - packetVersionMatch(packetData)) { - - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - if (packetData[0] == PACKET_TYPE_PARTICLE_QUERY) { - bool debug = false; - if (debug) { - qDebug("Got PACKET_TYPE_PARTICLE_QUERY at %llu.\n", usecTimestampNow()); - } - - // If we got a PACKET_TYPE_PARTICLE_QUERY, then we're talking to an NODE_TYPE_AVATAR, and we - // need to make sure we have it in our nodeList. - QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader, - NUM_BYTES_RFC4122_UUID)); - - Node* node = nodeList->nodeWithUUID(nodeUUID); - - if (node) { - nodeList->updateNodeWithData(node, &senderAddress, packetData, packetLength); - if (!node->getActiveSocket()) { - // we don't have an active socket for this node, but they're talking to us - // this means they've heard from us and can reply, let's assume public is active - node->activatePublicSocket(); - } - ParticleReceiverData* nodeData = (ParticleReceiverData*) node->getLinkedData(); - if (nodeData && !nodeData->isParticleSendThreadInitalized()) { - nodeData->initializeParticleSendThread(this); - } - } - } else if (packetData[0] == PACKET_TYPE_PARTICLE_JURISDICTION_REQUEST) { - if (_jurisdictionSender) { - _jurisdictionSender->queueReceivedPacket(senderAddress, packetData, packetLength); - } - } else if (_particleServerPacketProcessor && - (packetData[0] == PACKET_TYPE_SET_VOXEL - || packetData[0] == PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE - || packetData[0] == PACKET_TYPE_ERASE_VOXEL)) { - - - const char* messageName; - switch (packetData[0]) { - case PACKET_TYPE_SET_VOXEL: - messageName = "PACKET_TYPE_SET_VOXEL"; - break; - case PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE: - messageName = "PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE"; - break; - case PACKET_TYPE_ERASE_VOXEL: - messageName = "PACKET_TYPE_ERASE_VOXEL"; - break; - } - _particleServerPacketProcessor->queueReceivedPacket(senderAddress, packetData, packetLength); - } else { - // let processNodeData handle it. - NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength); - } - } - } - - // call NodeList::clear() so that all of our node specific objects, including our sending threads, are - // properly shutdown and cleaned up. - NodeList::getInstance()->clear(); - - if (_jurisdictionSender) { - _jurisdictionSender->terminate(); - delete _jurisdictionSender; - } - - if (_particleServerPacketProcessor) { - _particleServerPacketProcessor->terminate(); - delete _particleServerPacketProcessor; - } - - if (_particlePersistThread) { - _particlePersistThread->terminate(); - delete _particlePersistThread; - } - - // tell our NodeList we're done with notifications - nodeList->removeHook(&_nodeWatcher); - - delete _jurisdiction; - _jurisdiction = NULL; - - qDebug() << "ParticleSever::run()... DONE\n"; -} - - -void ParticleSever::nodeAdded(Node* node) { - // do nothing -} - -void ParticleSever::nodeKilled(Node* node) { - // Use this to cleanup our node - if (node->getType() == NODE_TYPE_AGENT) { - ParticleReceiverData* nodeData = (ParticleReceiverData*)node->getLinkedData(); - if (nodeData) { - node->setLinkedData(NULL); - delete nodeData; - } - } -}; diff --git a/libraries/particle-server/src/ParticleServer.h b/libraries/particle-server/src/ParticleServer.h deleted file mode 100644 index d33bcd8eaa..0000000000 --- a/libraries/particle-server/src/ParticleServer.h +++ /dev/null @@ -1,91 +0,0 @@ -// -// ParticleServer.h -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// - -#ifndef __particle_server__ParticleServer__ -#define __particle_server__ParticleServer__ - -#include -#include -#include - -#include - -#include "civetweb.h" - -#include "ParticlePersistThread.h" -#include "ParticleSendThread.h" -#include "ParticleServerConsts.h" -#include "ParticleServerPacketProcessor.h" - -/// Handles assignments of type ParticleServer - sending particles to various clients. -class ParticleServer : public Assignment { -public: - ParticleServer(const unsigned char* dataBuffer, int numBytes); - - ~ParticleServer(); - - /// runs the particle server assignment - void run(); - - /// allows setting of run arguments - void setArguments(int argc, char** argv); - - bool wantsDebugParticleSending() const { return _debugParticleSending; } - bool wantsDebugParticleReceiving() const { return _debugParticleReceiving; } - bool wantsVerboseDebug() const { return _verboseDebug; } - bool wantShowAnimationDebug() const { return _shouldShowAnimationDebug; } - bool wantDumpParticlesOnMove() const { return _dumpParticlesOnMove; } - bool wantDisplayParticleStats() const { return _displayParticleStats; } - - ParticleTree& getServerTree() { return _serverTree; } - JurisdictionMap* getJurisdiction() { return _jurisdiction; } - - int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; } - - static ParticleServer* GetInstance() { return _theInstance; } - - bool isInitialLoadComplete() const { return (_particlePersistThread) ? _particlePersistThread->isInitialLoadComplete() : true; } - time_t* getLoadCompleted() { return (_particlePersistThread) ? _particlePersistThread->getLoadCompleted() : NULL; } - uint64_t getLoadElapsedTime() const { return (_particlePersistThread) ? _particlePersistThread->getLoadElapsedTime() : 0; } - -private: - int _argc; - const char** _argv; - char** _parsedArgV; - - char _particlePersistFilename[MAX_FILENAME_LENGTH]; - int _packetsPerClientPerInterval; - ParticleTree _serverTree; // this IS a reaveraging tree - bool _wantParticlePersist; - bool _wantLocalDomain; - bool _debugParticleSending; - bool _shouldShowAnimationDebug; - bool _displayParticleStats; - bool _debugParticleReceiving; - bool _dumpParticlesOnMove; - bool _verboseDebug; - JurisdictionMap* _jurisdiction; - JurisdictionSender* _jurisdictionSender; - ParticleServerPacketProcessor* _particleServerPacketProcessor; - ParticlePersistThread* _particlePersistThread; - - NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed - - void parsePayload(); - - void initMongoose(int port); - - static int civetwebRequestHandler(struct mg_connection *connection); - static ParticleServer* _theInstance; - - time_t _started; - uint64_t _startedUSecs; -}; - -#endif // __particle_server__ParticleServer__ diff --git a/libraries/particle-server/src/ParticleServerConsts.h b/libraries/particle-server/src/ParticleServerConsts.h deleted file mode 100644 index 5940674443..0000000000 --- a/libraries/particle-server/src/ParticleServerConsts.h +++ /dev/null @@ -1,28 +0,0 @@ -// ParticleServerConsts.h -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// - -#ifndef __particle_server__ParticleServerConsts__ -#define __particle_server__ParticleServerConsts__ - -#include -#include // for MAX_PACKET_SIZE -#include -#include - -#include "ParticleServerPacketProcessor.h" - -const int MAX_FILENAME_LENGTH = 1024; -const int INTERVALS_PER_SECOND = 60; -const int PARTICLE_SEND_INTERVAL_USECS = (1000 * 1000)/INTERVALS_PER_SECOND; -const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating particles -const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000; - -extern const char* LOCAL_PARTICLES_PERSIST_FILE; -extern const char* PARTICLES_PERSIST_FILE; - -#endif // __particle_server__ParticleServerConsts__ diff --git a/libraries/particle-server/src/ParticleServerPacketProcessor.cpp b/libraries/particle-server/src/ParticleServerPacketProcessor.cpp deleted file mode 100644 index 9d0b771c8e..0000000000 --- a/libraries/particle-server/src/ParticleServerPacketProcessor.cpp +++ /dev/null @@ -1,222 +0,0 @@ -// -// ParticleServerPacketProcessor.cpp -// particle-server -// -// Created by Brad Hefta-Gaub on 12/2/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded network packet processor for the particle-server -// - -#include -#include - -#include "ParticleServer.h" -#include "ParticleServerConsts.h" -#include "ParticleServerPacketProcessor.h" - -static QUuid DEFAULT_NODE_ID_REF; - -ParticleServerPacketProcessor::ParticleServerPacketProcessor(ParticleServer* myServer) : - _myServer(myServer), - _receivedPacketCount(0), - _totalTransitTime(0), - _totalProcessTime(0), - _totalLockWaitTime(0), - _totalParticlesInPacket(0), - _totalPackets(0) -{ -} - -void ParticleServerPacketProcessor::resetStats() { - _totalTransitTime = 0; - _totalProcessTime = 0; - _totalLockWaitTime = 0; - _totalParticlesInPacket = 0; - _totalPackets = 0; - - _singleSenderStats.clear(); -} - - -void ParticleServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) { - - bool debugProcessPacket = _myServer->wantsVerboseDebug(); - - if (debugProcessPacket) { - printf("ParticleServerPacketProcessor::processPacket() packetData=%p packetLength=%ld\n", packetData, packetLength); - } - - int numBytesPacketHeader = numBytesForPacketHeader(packetData); - - if (packetData[0] == PACKET_TYPE_SET_PARTICLE || packetData[0] == PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE) { - bool destructive = (packetData[0] == PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE); - PerformanceWarning warn(_myServer->wantShowAnimationDebug(), - destructive ? "PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE" : "PACKET_TYPE_SET_PARTICLE", - _myServer->wantShowAnimationDebug()); - - _receivedPacketCount++; - - unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); - uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); - uint64_t arrivedAt = usecTimestampNow(); - uint64_t transitTime = arrivedAt - sentAt; - int particlesInPacket = 0; - uint64_t processTime = 0; - uint64_t lockWaitTime = 0; - - if (_myServer->wantShowAnimationDebug() || _myServer->wantsDebugParticleReceiving()) { - printf("PROCESSING THREAD: got %s - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", - destructive ? "PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE" : "PACKET_TYPE_SET_PARTICLE", - _receivedPacketCount, packetLength, sequence, transitTime); - } - int atByte = numBytesPacketHeader + sizeof(sequence) + sizeof(sentAt); - unsigned char* particleData = (unsigned char*)&packetData[atByte]; - while (atByte < packetLength) { - int maxSize = packetLength - atByte; - - if (debugProcessPacket) { - printf("ParticleServerPacketProcessor::processPacket() %s packetData=%p packetLength=%ld particleData=%p atByte=%d maxSize=%d\n", - destructive ? "PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE" : "PACKET_TYPE_SET_PARTICLE", - packetData, packetLength, particleData, atByte, maxSize); - } - - int octets = numberOfThreeBitSectionsInCode(particleData, maxSize); - - if (octets == OVERFLOWED_OCTCODE_BUFFER) { - printf("WARNING! Got particle edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), "); - printf("bailing processing of packet!\n"); - break; - } - - const int COLOR_SIZE_IN_BYTES = 3; - int particleDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES; - int particleCodeSize = bytesRequiredForCodeLength(octets); - - if (atByte + particleDataSize <= packetLength) { - if (_myServer->wantShowAnimationDebug()) { - int red = particleData[particleCodeSize + RED_INDEX]; - int green = particleData[particleCodeSize + GREEN_INDEX]; - int blue = particleData[particleCodeSize + BLUE_INDEX]; - - float* vertices = firstVertexForCode(particleData); - printf("inserting particle: %f,%f,%f r=%d,g=%d,b=%d\n", vertices[0], vertices[1], vertices[2], red, green, blue); - delete[] vertices; - } - - uint64_t startLock = usecTimestampNow(); - _myServer->getServerTree().lockForWrite(); - uint64_t startProcess = usecTimestampNow(); - _myServer->getServerTree().readCodeColorBufferToTree(particleData, destructive); - _myServer->getServerTree().unlock(); - uint64_t endProcess = usecTimestampNow(); - - particlesInPacket++; - - uint64_t thisProcessTime = endProcess - startProcess; - uint64_t thisLockWaitTime = startProcess - startLock; - - processTime += thisProcessTime; - lockWaitTime += thisLockWaitTime; - - // skip to next particle edit record in the packet - particleData += particleDataSize; - atByte += particleDataSize; - } else { - printf("WARNING! Got particle edit record that would overflow buffer, bailing processing of packet!\n"); - break; - } - } - - if (debugProcessPacket) { - printf("ParticleServerPacketProcessor::processPacket() DONE LOOPING FOR %s packetData=%p packetLength=%ld particleData=%p atByte=%d\n", - destructive ? "PACKET_TYPE_SET_PARTICLE_DESTRUCTIVE" : "PACKET_TYPE_SET_PARTICLE", - packetData, packetLength, particleData, atByte); - } - - // Make sure our Node and NodeList knows we've heard from this node. - Node* senderNode = NodeList::getInstance()->nodeWithAddress(&senderAddress); - QUuid& nodeUUID = DEFAULT_NODE_ID_REF; - if (senderNode) { - senderNode->setLastHeardMicrostamp(usecTimestampNow()); - nodeUUID = senderNode->getUUID(); - if (debugProcessPacket) { - qDebug() << "sender has uuid=" << nodeUUID << "\n"; - } - } else { - if (debugProcessPacket) { - qDebug() << "sender has no known nodeUUID.\n"; - } - } - trackInboundPackets(nodeUUID, sequence, transitTime, particlesInPacket, processTime, lockWaitTime); - - } else if (packetData[0] == PACKET_TYPE_ERASE_PARTICLE) { - - _receivedPacketCount++; - - unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader))); - uint64_t sentAt = (*((uint64_t*)(packetData + numBytesPacketHeader + sizeof(sequence)))); - uint64_t arrivedAt = usecTimestampNow(); - uint64_t transitTime = arrivedAt - sentAt; - - if (_myServer->wantShowAnimationDebug() || _myServer->wantsDebugParticleReceiving()) { - printf("PROCESSING THREAD: got PACKET_TYPE_ERASE_PARTICLE - %d command from client receivedBytes=%ld sequence=%d transitTime=%llu usecs\n", - _receivedPacketCount, packetLength, sequence, transitTime); - } - - // Send these bits off to the ParticleTree class to process them - _myServer->getServerTree().lockForWrite(); - _myServer->getServerTree().processRemoveParticleBitstream((unsigned char*)packetData, packetLength); - _myServer->getServerTree().unlock(); - - // Make sure our Node and NodeList knows we've heard from this node. - Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress); - if (node) { - node->setLastHeardMicrostamp(usecTimestampNow()); - } - } else { - printf("unknown packet ignored... packetData[0]=%c\n", packetData[0]); - } -} - -void ParticleServerPacketProcessor::trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, - int particlesInPacket, uint64_t processTime, uint64_t lockWaitTime) { - - _totalTransitTime += transitTime; - _totalProcessTime += processTime; - _totalLockWaitTime += lockWaitTime; - _totalParticlesInPacket += particlesInPacket; - _totalPackets++; - - // find the individual senders stats and track them there too... - // see if this is the first we've heard of this node... - if (_singleSenderStats.find(nodeUUID) == _singleSenderStats.end()) { - SingleSenderStats stats; - - stats._totalTransitTime += transitTime; - stats._totalProcessTime += processTime; - stats._totalLockWaitTime += lockWaitTime; - stats._totalParticlesInPacket += particlesInPacket; - stats._totalPackets++; - - _singleSenderStats[nodeUUID] = stats; - } else { - SingleSenderStats& stats = _singleSenderStats[nodeUUID]; - stats._totalTransitTime += transitTime; - stats._totalProcessTime += processTime; - stats._totalLockWaitTime += lockWaitTime; - stats._totalParticlesInPacket += particlesInPacket; - stats._totalPackets++; - } -} - - -SingleSenderStats::SingleSenderStats() { - _totalTransitTime = 0; - _totalProcessTime = 0; - _totalLockWaitTime = 0; - _totalParticlesInPacket = 0; - _totalPackets = 0; -} - - diff --git a/libraries/particle-server/src/ParticleServerPacketProcessor.h b/libraries/particle-server/src/ParticleServerPacketProcessor.h deleted file mode 100644 index 1b4c2b87b1..0000000000 --- a/libraries/particle-server/src/ParticleServerPacketProcessor.h +++ /dev/null @@ -1,83 +0,0 @@ -// -// ParticleServerPacketProcessor.h -// particle-server -// -// Created by Brad Hefta-Gaub on 8/21/13 -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// -// Threaded or non-threaded network packet processor for the particle-server -// - -#ifndef __particle_server__ParticleServerPacketProcessor__ -#define __particle_server__ParticleServerPacketProcessor__ - -#include - -#include -class ParticleServer; - -class SingleSenderStats { -public: - SingleSenderStats(); - - uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } - uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } - uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } - uint64_t getTotalParticlesProcessed() const { return _totalParticlesInPacket; } - uint64_t getTotalPacketsProcessed() const { return _totalPackets; } - uint64_t getAverageProcessTimePerParticle() const - { return _totalParticlesInPacket == 0 ? 0 : _totalProcessTime / _totalParticlesInPacket; } - uint64_t getAverageLockWaitTimePerParticle() const - { return _totalParticlesInPacket == 0 ? 0 : _totalLockWaitTime / _totalParticlesInPacket; } - - uint64_t _totalTransitTime; - uint64_t _totalProcessTime; - uint64_t _totalLockWaitTime; - uint64_t _totalParticlesInPacket; - uint64_t _totalPackets; -}; - -typedef std::map NodeToSenderStatsMap; -typedef std::map::iterator NodeToSenderStatsMapIterator; - - -/// Handles processing of incoming network packets for the particle-server. As with other ReceivedPacketProcessor classes -/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() -class ParticleServerPacketProcessor : public ReceivedPacketProcessor { - -public: - ParticleServerPacketProcessor(ParticleServer* myServer); - - uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } - uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } - uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } - uint64_t getTotalParticlesProcessed() const { return _totalParticlesInPacket; } - uint64_t getTotalPacketsProcessed() const { return _totalPackets; } - uint64_t getAverageProcessTimePerParticle() const - { return _totalParticlesInPacket == 0 ? 0 : _totalProcessTime / _totalParticlesInPacket; } - uint64_t getAverageLockWaitTimePerParticle() const - { return _totalParticlesInPacket == 0 ? 0 : _totalLockWaitTime / _totalParticlesInPacket; } - - void resetStats(); - - NodeToSenderStatsMap& getSingleSenderStats() { return _singleSenderStats; } - -protected: - virtual void processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); - -private: - void trackInboundPackets(const QUuid& nodeUUID, int sequence, uint64_t transitTime, - int particlesInPacket, uint64_t processTime, uint64_t lockWaitTime); - - ParticleServer* _myServer; - int _receivedPacketCount; - - uint64_t _totalTransitTime; - uint64_t _totalProcessTime; - uint64_t _totalLockWaitTime; - uint64_t _totalParticlesInPacket; - uint64_t _totalPackets; - - NodeToSenderStatsMap _singleSenderStats; -}; -#endif // __particle_server__ParticleServerPacketProcessor__ diff --git a/libraries/particles/CMakeLists.txt b/libraries/particles/CMakeLists.txt deleted file mode 100644 index 3bbff3b433..0000000000 --- a/libraries/particles/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -cmake_minimum_required(VERSION 2.8) - -set(ROOT_DIR ../..) -set(MACRO_DIR ${ROOT_DIR}/cmake/macros) - -# setup for find modules -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") - -set(TARGET_NAME particles) - -find_package(Qt5Widgets REQUIRED) - -include(${MACRO_DIR}/SetupHifiLibrary.cmake) -setup_hifi_library(${TARGET_NAME}) - -qt5_use_modules(${TARGET_NAME} Widgets) - -include(${MACRO_DIR}/IncludeGLM.cmake) -include_glm(${TARGET_NAME} ${ROOT_DIR}) - -include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) - -# link ZLIB -find_package(ZLIB) -include_directories(${ZLIB_INCLUDE_DIRS}) -target_link_libraries(${TARGET_NAME} ${ZLIB_LIBRARIES}) diff --git a/libraries/particles/src/ParticleTree.cpp b/libraries/particles/src/ParticleTree.cpp deleted file mode 100644 index a8215ba4cf..0000000000 --- a/libraries/particles/src/ParticleTree.cpp +++ /dev/null @@ -1 +0,0 @@ -// ParticleTree.cpp \ No newline at end of file