Merge pull request #1176 from ZappoMan/bugfixes

fix oversending bug
This commit is contained in:
Philip Rosedale 2013-11-04 13:36:47 -08:00
commit 11e6982a9d
3 changed files with 49 additions and 25 deletions

View file

@ -24,7 +24,7 @@ VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) :
} }
bool VoxelSendThread::process() { bool VoxelSendThread::process() {
uint64_t lastSendTime = usecTimestampNow(); uint64_t start = usecTimestampNow();
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID); Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
VoxelNodeData* nodeData = NULL; VoxelNodeData* nodeData = NULL;
@ -32,6 +32,8 @@ bool VoxelSendThread::process() {
if (node) { if (node) {
nodeData = (VoxelNodeData*) node->getLinkedData(); nodeData = (VoxelNodeData*) node->getLinkedData();
} }
int packetsSent = 0;
// Sometimes the node data has not yet been linked, in which case we can't really do anything // Sometimes the node data has not yet been linked, in which case we can't really do anything
if (nodeData) { if (nodeData) {
@ -39,11 +41,12 @@ bool VoxelSendThread::process() {
if (_myServer->wantsDebugVoxelSending()) { if (_myServer->wantsDebugVoxelSending()) {
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged)); printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
} }
deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged); packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
} }
// dynamically sleep until we need to fire off the next set of voxels // dynamically sleep until we need to fire off the next set of voxels
int usecToSleep = VOXEL_SEND_INTERVAL_USECS - (usecTimestampNow() - lastSendTime); int elapsed = (usecTimestampNow() - start);
int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed;
if (usecToSleep > 0) { if (usecToSleep > 0) {
usleep(usecToSleep); usleep(usecToSleep);
@ -52,19 +55,19 @@ bool VoxelSendThread::process() {
std::cout << "Last send took too much time, not sleeping!\n"; std::cout << "Last send took too much time, not sleeping!\n";
} }
} }
return isStillRunning(); // keep running till they terminate us return isStillRunning(); // keep running till they terminate us
} }
void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) { int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent) {
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 // 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 // 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. // this rate control savings.
if (nodeData->shouldSuppressDuplicatePacket()) { if (nodeData->shouldSuppressDuplicatePacket()) {
nodeData->resetVoxelPacket(); // we still need to reset it though! nodeData->resetVoxelPacket(); // we still need to reset it though!
return; // without sending... return packetsSent; // without sending...
} }
// If we've got a stats message ready to send, then see if we can piggyback them together // If we've got a stats message ready to send, then see if we can piggyback them together
@ -85,6 +88,10 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
} else { } else {
// not enough room in the packet, send two packets // not enough room in the packet, send two packets
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength); NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), statsMessage, statsMessageLength);
trueBytesSent += statsMessageLength;
truePacketsSent++;
packetsSent++;
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength()); nodeData->getPacket(), nodeData->getPacketLength());
} }
@ -97,16 +104,21 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
nodeData->stats.packetSent(nodeData->getPacketLength()); nodeData->stats.packetSent(nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength(); trueBytesSent += nodeData->getPacketLength();
truePacketsSent++; truePacketsSent++;
packetsSent++;
nodeData->resetVoxelPacket(); nodeData->resetVoxelPacket();
return packetsSent;
} }
/// Version of voxel distributor that sends the deepest LOD level at once /// Version of voxel distributor that sends the deepest LOD level at once
void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) { int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) {
_myServer->lockTree(); _myServer->lockTree();
int truePacketsSent = 0; int truePacketsSent = 0;
int trueBytesSent = 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 // FOR NOW... node tells us if it wants to receive only view frustum deltas
bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();
@ -127,8 +139,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor())); debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
} }
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
} else { } else {
if (_myServer->wantsDebugVoxelSending()) { if (_myServer->wantsDebugVoxelSending()) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n", printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
@ -217,21 +228,26 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
// If we have something in our nodeBag, then turn them into packets and send them out... // If we have something in our nodeBag, then turn them into packets and send them out...
if (!nodeData->nodeBag.isEmpty()) { if (!nodeData->nodeBag.isEmpty()) {
int bytesWritten = 0; int bytesWritten = 0;
int packetsSentThisInterval = 0;
uint64_t start = usecTimestampNow(); uint64_t start = usecTimestampNow();
bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS); bool shouldSendEnvironments = _myServer->wantSendEnvironments() && shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
int clientMaxPacketsPerInterval = nodeData->getMaxVoxelPacketsPerSecond() / INTERVALS_PER_SECOND; int clientMaxPacketsPerInterval = std::max(1,(nodeData->getMaxVoxelPacketsPerSecond() / INTERVALS_PER_SECOND));
int maxPacketsPerInterval = std::max(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval()); int maxPacketsPerInterval = std::min(clientMaxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval());
if (_myServer->wantsDebugVoxelSending()) { if (_myServer->wantsDebugVoxelSending()) {
printf("packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n", printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(), truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval); nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval);
} }
while (somethingToSend && packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) {
if (_myServer->wantsDebugVoxelSending()) {
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval);
}
while (packetsSentThisInterval < maxPacketsPerInterval - (shouldSendEnvironments ? 1 : 0)) {
// Check to see if we're taking too long, and if so bail early... // Check to see if we're taking too long, and if so bail early...
uint64_t now = usecTimestampNow(); uint64_t now = usecTimestampNow();
long elapsedUsec = (now - start); long elapsedUsec = (now - start);
@ -276,17 +292,18 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
if (nodeData->getAvailable() >= bytesWritten) { if (nodeData->getAvailable() >= bytesWritten) {
nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); nodeData->writeToPacket(_tempOutputBuffer, bytesWritten);
} else { } else {
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
packetsSentThisInterval++;
nodeData->writeToPacket(_tempOutputBuffer, bytesWritten); nodeData->writeToPacket(_tempOutputBuffer, bytesWritten);
} }
} else { } else {
if (nodeData->isPacketWaiting()) { if (nodeData->isPacketWaiting()) {
handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
} }
packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left //packetsSentThisInterval = _myServer->getPacketsPerClientPerInterval(); // done for now, no nodes left
somethingToSend = false;
} }
} }
// send the environment packet // send the environment packet
if (shouldSendEnvironments) { if (shouldSendEnvironments) {
int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA); int numBytesPacketHeader = populateTypeAndVersion(_tempOutputBuffer, PACKET_TYPE_ENVIRONMENT_DATA);
@ -300,6 +317,7 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength); NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(), _tempOutputBuffer, envPacketLength);
trueBytesSent += envPacketLength; trueBytesSent += envPacketLength;
truePacketsSent++; truePacketsSent++;
packetsSentThisInterval++;
} }
uint64_t end = usecTimestampNow(); uint64_t end = usecTimestampNow();
@ -328,9 +346,17 @@ void VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* no
} }
nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes
} }
if (_myServer->wantsDebugVoxelSending()) {
printf("truePacketsSent=%d packetsSentThisInterval=%d maxPacketsPerInterval=%d server PPI=%d nodePPS=%d nodePPI=%d\n",
truePacketsSent, packetsSentThisInterval, maxPacketsPerInterval, _myServer->getPacketsPerClientPerInterval(),
nodeData->getMaxVoxelPacketsPerSecond(), clientMaxPacketsPerInterval);
}
} // end if bag wasn't empty, and so we sent stuff... } // end if bag wasn't empty, and so we sent stuff...
_myServer->unlockTree(); _myServer->unlockTree();
return truePacketsSent;
} }

View file

@ -30,8 +30,8 @@ private:
QUuid _nodeUUID; QUuid _nodeUUID;
VoxelServer* _myServer; VoxelServer* _myServer;
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent); int handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
void deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged); int deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged);
unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE]; unsigned char _tempOutputBuffer[MAX_VOXEL_PACKET_SIZE];
}; };

View file

@ -18,11 +18,9 @@
const int MAX_FILENAME_LENGTH = 1024; const int MAX_FILENAME_LENGTH = 1024;
const int VOXEL_SIZE_BYTES = 3 + (3 * sizeof(float)); const int INTERVALS_PER_SECOND = 60;
const int VOXELS_PER_PACKET = (MAX_PACKET_SIZE - 1) / VOXEL_SIZE_BYTES; const int VOXEL_SEND_INTERVAL_USECS = (1000 * 1000)/INTERVALS_PER_SECOND;
const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps
const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels
const int INTERVALS_PER_SECOND = 1000 * 1000 / VOXEL_SEND_INTERVAL_USECS;
const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000; const int ENVIRONMENT_SEND_INTERVAL_USECS = 1000000;
extern const char* LOCAL_VOXELS_PERSIST_FILE; extern const char* LOCAL_VOXELS_PERSIST_FILE;