Merge pull request #3744 from ZappoMan/entityBugs

Octree server improvements
This commit is contained in:
Philip Rosedale 2014-11-06 08:41:21 -08:00
commit 7e822d31e7
14 changed files with 359 additions and 147 deletions

View file

@ -34,6 +34,7 @@ public:
virtual const char* getMyLoggingServerTargetName() const { return MODEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_MODELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const { return PacketTypeEntityEditNack; }
virtual QString getMyDomainSettingsKey() const { return QString("entity_server_settings"); }
// subclass may implement these method
virtual void beforeRun();

View file

@ -98,15 +98,28 @@ void OctreeInboundPacketProcessor::processPacket(const SharedNodePointer& sendin
unsigned short int sequence = (*((unsigned short int*)(packetData + numBytesPacketHeader)));
quint64 sentAt = (*((quint64*)(packetData + numBytesPacketHeader + sizeof(sequence))));
quint64 arrivedAt = usecTimestampNow();
if (sentAt > arrivedAt) {
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
qDebug() << "unreasonable sentAt=" << sentAt << " usecs";
qDebug() << "setting sentAt to arrivedAt=" << arrivedAt << " usecs";
}
sentAt = arrivedAt;
}
quint64 transitTime = arrivedAt - sentAt;
int editsInPacket = 0;
quint64 processTime = 0;
quint64 lockWaitTime = 0;
if (debugProcessPacket || _myServer->wantsDebugReceiving()) {
qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount
<< " command from client receivedBytes=" << packet.size()
<< " sequence=" << sequence << " transitTime=" << transitTime << " usecs";
qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client";
qDebug() << " receivedBytes=" << packet.size();
qDebug() << " sequence=" << sequence;
qDebug() << " sentAt=" << sentAt << " usecs";
qDebug() << " arrivedAt=" << arrivedAt << " usecs";
qDebug() << " transitTime=" << transitTime << " usecs";
qDebug() << " sendingNode->getClockSkewUsec()=" << sendingNode->getClockSkewUsec() << " usecs";
}
if (debugProcessPacket) {

View file

@ -900,85 +900,206 @@ void OctreeServer::setupDatagramProcessingThread() {
// start the datagram processing thread
_datagramProcessingThread->start();
}
bool OctreeServer::readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result) {
result = false; // assume it doesn't exist
bool optionAvailable = false;
QString argName = "--" + optionName;
bool argExists = cmdOptionExists(_argc, _argv, qPrintable(argName));
if (argExists) {
optionAvailable = true;
result = argExists;
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toBool();
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
return optionAvailable;
}
bool OctreeServer::readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = atoi(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << result;
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString().toInt(&optionAvailable);
if (optionAvailable) {
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << result;
}
}
return optionAvailable;
}
bool OctreeServer::readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result) {
bool optionAvailable = false;
QString argName = "--" + optionName;
const char* argValue = getCmdOption(_argc, _argv, qPrintable(argName));
if (argValue) {
optionAvailable = true;
result = QString(argValue);
qDebug() << "From payload arguments: " << qPrintable(argName) << ":" << qPrintable(result);
} else if (settingsSectionObject.contains(optionName)) {
optionAvailable = true;
result = settingsSectionObject[optionName].toString();
qDebug() << "From domain settings: " << qPrintable(optionName) << ":" << qPrintable(result);
}
return optionAvailable;
}
void OctreeServer::readConfiguration() {
// if the assignment had a payload, read and parse that
if (getPayload().size() > 0) {
parsePayload();
}
// wait until we have the domain-server settings, otherwise we bail
NodeList* nodeList = NodeList::getInstance();
DomainHandler& domainHandler = nodeList->getDomainHandler();
qDebug() << "Waiting for domain settings from domain-server.";
// block until we get the settingsRequestComplete signal
QEventLoop loop;
connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
domainHandler.requestDomainSettings();
loop.exec();
if (domainHandler.getSettingsObject().isEmpty()) {
qDebug() << "No settings object from domain-server.";
}
const QJsonObject& settingsObject = domainHandler.getSettingsObject();
QString settingsKey = getMyDomainSettingsKey();
QJsonObject settingsSectionObject = settingsObject[settingsKey].toObject();
if (!readOptionString(QString("statusHost"), settingsSectionObject, _statusHost) || _statusHost.isEmpty()) {
_statusHost = getLocalAddress().toString();
}
qDebug("statusHost=%s", qPrintable(_statusHost));
if (readOptionInt(QString("statusPort"), settingsSectionObject, _statusPort)) {
initHTTPManager(_statusPort);
qDebug() << "statusPort=" << _statusPort;
} else {
qDebug() << "statusPort= DISABLED";
}
QString jurisdictionFile;
if (readOptionString(QString("jurisdictionFile"), settingsSectionObject, jurisdictionFile)) {
qDebug("jurisdictionFile=%s", qPrintable(jurisdictionFile));
qDebug("about to readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile));
_jurisdiction = new JurisdictionMap(qPrintable(jurisdictionFile));
qDebug("after readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile));
} else {
QString jurisdictionRoot;
bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot);
QString jurisdictionEndNodes;
bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes);
if (hasRoot || hasEndNodes) {
_jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes));
}
}
readOptionBool(QString("verboseDebug"), settingsSectionObject, _verboseDebug);
qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug));
readOptionBool(QString("debugSending"), settingsSectionObject, _debugSending);
qDebug("debugSending=%s", debug::valueOf(_debugSending));
readOptionBool(QString("debugReceiving"), settingsSectionObject, _debugReceiving);
qDebug("debugReceiving=%s", debug::valueOf(_debugReceiving));
bool noPersist;
readOptionBool(QString("NoPersist"), settingsSectionObject, noPersist);
_wantPersist = !noPersist;
qDebug("wantPersist=%s", debug::valueOf(_wantPersist));
if (_wantPersist) {
QString persistFilename;
if (!readOptionString(QString("persistFilename"), settingsSectionObject, persistFilename)) {
persistFilename = getMyDefaultPersistFilename();
}
strcpy(_persistFilename, qPrintable(persistFilename));
qDebug("persistFilename=%s", _persistFilename);
} else {
qDebug("persistFilename= DISABLED");
}
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
int clockSkew;
if (readOptionInt(QString("clockSkew"), settingsSectionObject, clockSkew)) {
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkew=%d", clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate
int packetsPerSecondPerClientMax = -1;
if (readOptionInt(QString("packetsPerSecondPerClientMax"), settingsSectionObject, packetsPerSecondPerClientMax)) {
_packetsPerClientPerInterval = packetsPerSecondPerClientMax / INTERVALS_PER_SECOND;
if (_packetsPerClientPerInterval < 1) {
_packetsPerClientPerInterval = 1;
}
}
qDebug("packetsPerSecondPerClientMax=%d _packetsPerClientPerInterval=%d",
packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
// Check to see if the user passed in a command line option for setting packet send rate
int packetsPerSecondTotalMax = -1;
if (readOptionInt(QString("packetsPerSecondTotalMax"), settingsSectionObject, packetsPerSecondTotalMax)) {
_packetsTotalPerInterval = packetsPerSecondTotalMax / INTERVALS_PER_SECOND;
if (_packetsTotalPerInterval < 1) {
_packetsTotalPerInterval = 1;
}
}
qDebug("packetsPerSecondTotalMax=%d _packetsTotalPerInterval=%d",
packetsPerSecondTotalMax, _packetsTotalPerInterval);
readAdditionalConfiguration(settingsSectionObject);
}
void OctreeServer::run() {
qInstallMessageHandler(LogHandler::verboseMessageHandler);
_safeServerName = getMyServerName();
// Before we do anything else, create our tree...
OctreeElement::resetPopulationStatistics();
_tree = createTree();
_tree->setIsServer(true);
// make sure our NodeList knows what type we are
NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(getMyNodeType());
// use common init to setup common timers and logging
commonInit(getMyLoggingServerTargetName(), getMyNodeType());
setupDatagramProcessingThread();
// Now would be a good time to parse our arguments, if we got them as assignment
if (getPayload().size() > 0) {
parsePayload();
}
// read the configuration from either the payload or the domain server configuration
readConfiguration();
beforeRun(); // after payload has been processed
qInstallMessageHandler(LogHandler::verboseMessageHandler);
const char* STATUS_PORT = "--statusPort";
const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT);
if (statusPort) {
_statusPort = atoi(statusPort);
initHTTPManager(_statusPort);
}
const char* STATUS_HOST = "--statusHost";
const char* statusHost = getCmdOption(_argc, _argv, STATUS_HOST);
if (statusHost) {
qDebug("--statusHost=%s", statusHost);
_statusHost = statusHost;
} else {
_statusHost = getLocalAddress().toString();
}
qDebug("statusHost=%s", qPrintable(_statusHost));
const char* JURISDICTION_FILE = "--jurisdictionFile";
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
if (jurisdictionFile) {
qDebug("jurisdictionFile=%s", jurisdictionFile);
qDebug("about to readFromFile().... jurisdictionFile=%s", jurisdictionFile);
_jurisdiction = new JurisdictionMap(jurisdictionFile);
qDebug("after readFromFile().... jurisdictionFile=%s", jurisdictionFile);
} else {
const char* JURISDICTION_ROOT = "--jurisdictionRoot";
const char* jurisdictionRoot = getCmdOption(_argc, _argv, JURISDICTION_ROOT);
if (jurisdictionRoot) {
qDebug("jurisdictionRoot=%s", jurisdictionRoot);
}
const char* JURISDICTION_ENDNODES = "--jurisdictionEndNodes";
const char* jurisdictionEndNodes = getCmdOption(_argc, _argv, JURISDICTION_ENDNODES);
if (jurisdictionEndNodes) {
qDebug("jurisdictionEndNodes=%s", jurisdictionEndNodes);
}
if (jurisdictionRoot || jurisdictionEndNodes) {
_jurisdiction = new JurisdictionMap(jurisdictionRoot, jurisdictionEndNodes);
}
}
NodeList* nodeList = NodeList::getInstance();
nodeList->setOwnerType(getMyNodeType());
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(nodeAdded(SharedNodePointer)));
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)),SLOT(nodeKilled(SharedNodePointer)));
// we need to ask the DS about agents so we can ping/reply with them
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
#ifndef WIN32
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
@ -987,39 +1108,9 @@ void OctreeServer::run() {
srand((unsigned)time(0));
const char* VERBOSE_DEBUG = "--verboseDebug";
_verboseDebug = cmdOptionExists(_argc, _argv, VERBOSE_DEBUG);
qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug));
const char* DEBUG_SENDING = "--debugSending";
_debugSending = cmdOptionExists(_argc, _argv, DEBUG_SENDING);
qDebug("debugSending=%s", debug::valueOf(_debugSending));
const char* DEBUG_RECEIVING = "--debugReceiving";
_debugReceiving = cmdOptionExists(_argc, _argv, DEBUG_RECEIVING);
qDebug("debugReceiving=%s", debug::valueOf(_debugReceiving));
// By default we will persist, if you want to disable this, then pass in this parameter
const char* NO_PERSIST = "--NoPersist";
if (cmdOptionExists(_argc, _argv, NO_PERSIST)) {
_wantPersist = false;
}
qDebug("wantPersist=%s", debug::valueOf(_wantPersist));
// if we want Persistence, set up the local file and persist thread
if (_wantPersist) {
// Check to see if the user passed in a command line option for setting packet send rate
const char* PERSIST_FILENAME = "--persistFilename";
const char* persistFilenameParameter = getCmdOption(_argc, _argv, PERSIST_FILENAME);
if (persistFilenameParameter) {
strcpy(_persistFilename, persistFilenameParameter);
} else {
strcpy(_persistFilename, getMyDefaultPersistFilename());
}
qDebug("persistFilename=%s", _persistFilename);
// now set up PersistThread
_persistThread = new OctreePersistThread(_tree, _persistFilename);
if (_persistThread) {
@ -1027,41 +1118,6 @@ void OctreeServer::run() {
}
}
// Debug option to demonstrate that the server's local time does not
// need to be in sync with any other network node. This forces clock
// skew for the individual server node
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(_argc, _argv, CLOCK_SKEW);
if (clockSkewOption) {
int clockSkew = atoi(clockSkewOption);
usecTimestampNowForceClockSkew(clockSkew);
qDebug("clockSkewOption=%s clockSkew=%d", clockSkewOption, clockSkew);
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND_PER_CLIENT_MAX = "--packetsPerSecondPerClientMax";
const char* packetsPerSecondPerClientMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_PER_CLIENT_MAX);
if (packetsPerSecondPerClientMax) {
_packetsPerClientPerInterval = atoi(packetsPerSecondPerClientMax) / INTERVALS_PER_SECOND;
if (_packetsPerClientPerInterval < 1) {
_packetsPerClientPerInterval = 1;
}
}
qDebug("packetsPerSecondPerClientMax=%s _packetsPerClientPerInterval=%d",
packetsPerSecondPerClientMax, _packetsPerClientPerInterval);
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND_TOTAL_MAX = "--packetsPerSecondTotalMax";
const char* packetsPerSecondTotalMax = getCmdOption(_argc, _argv, PACKETS_PER_SECOND_TOTAL_MAX);
if (packetsPerSecondTotalMax) {
_packetsTotalPerInterval = atoi(packetsPerSecondTotalMax) / INTERVALS_PER_SECOND;
if (_packetsTotalPerInterval < 1) {
_packetsTotalPerInterval = 1;
}
}
qDebug("packetsPerSecondTotalMax=%s _packetsTotalPerInterval=%d",
packetsPerSecondTotalMax, _packetsTotalPerInterval);
HifiSockAddr senderSockAddr;
// set up our jurisdiction broadcaster...

View file

@ -69,6 +69,7 @@ public:
virtual const char* getMyLoggingServerTargetName() const = 0;
virtual const char* getMyDefaultPersistFilename() const = 0;
virtual PacketType getMyEditNackType() const = 0;
virtual QString getMyDomainSettingsKey() const { return QString("octree_server_settings"); }
// subclass may implement these method
virtual void beforeRun() { }
@ -131,6 +132,11 @@ public slots:
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
protected:
bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result);
bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result);
bool readOptionString(const QString& optionName, const QJsonObject& settingsSectionObject, QString& result);
void readConfiguration();
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) { };
void parsePayload();
void initHTTPManager(int port);
void resetSendingStats();

View file

@ -82,18 +82,18 @@ int VoxelServer::sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNod
}
void VoxelServer::beforeRun() {
void VoxelServer::readAdditionalConfiguration(const QJsonObject& settingsSectionObject) {
// 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);
readOptionBool(QString("sendEnvironments"), settingsSectionObject, _sendEnvironments);
bool dontSendEnvironments = !_sendEnvironments;
if (dontSendEnvironments) {
qDebug("Sending environments suppressed...");
_sendEnvironments = false;
} else {
_sendEnvironments = true;
// should we send environments? Default is yes, but this command line suppresses sending
const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
//const char* MINIMAL_ENVIRONMENT = "--minimalEnvironment";
//_sendMinimalEnvironment = cmdOptionExists(_argc, _argv, MINIMAL_ENVIRONMENT);
readOptionBool(QString("minimalEnvironment"), settingsSectionObject, _sendMinimalEnvironment);
qDebug("Using Minimal Environment=%s", debug::valueOf(_sendMinimalEnvironment));
}
qDebug("Sending environments=%s", debug::valueOf(_sendEnvironments));

View file

@ -43,12 +43,15 @@ public:
virtual const char* getMyLoggingServerTargetName() const { return VOXEL_SERVER_LOGGING_TARGET_NAME; }
virtual const char* getMyDefaultPersistFilename() const { return LOCAL_VOXELS_PERSIST_FILE; }
virtual PacketType getMyEditNackType() const { return PacketTypeVoxelEditNack; }
virtual QString getMyDomainSettingsKey() const { return QString("voxel_server_settings"); }
// subclass may implement these method
virtual void beforeRun();
virtual bool hasSpecialPacketToSend(const SharedNodePointer& node);
virtual int sendSpecialPacket(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent);
protected:
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject);
private:
bool _sendEnvironments;
bool _sendMinimalEnvironment;

View file

@ -262,5 +262,106 @@
"advanced": true
}
]
}
},
{
"name": "entity_server_settings",
"label": "Entity Server Settings",
"assignment-types": [6],
"settings": [
{
"name": "statusHost",
"label": "Status Hostname",
"help": "host name or IP address of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "statusPort",
"label": "Status Port",
"help": "port of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "verboseDebug",
"type": "checkbox",
"help": "lots of debugging",
"default": false,
"advanced": true
},
{
"name": "debugReceiving",
"type": "checkbox",
"help": "extra debugging on receiving",
"default": false,
"advanced": true
},
{
"name": "debugSending",
"type": "checkbox",
"help": "extra debugging on sending",
"default": false,
"advanced": true
},
{
"name": "clockSkew",
"label": "Clock Skew",
"help": "Number of msecs to skew the server clock by to test clock skew",
"placeholder": "0",
"default": "0",
"advanced": true
}
]
},
{
"name": "voxel_server_settings",
"label": "Voxel Server Settings",
"assignment-types": [3],
"settings": [
{
"name": "statusHost",
"label": "Status Hostname",
"help": "host name or IP address of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "statusPort",
"label": "Status Port",
"help": "port of the server for accessing the status page",
"placeholder": "",
"default": "",
"advanced": true
},
{
"name": "clockSkew",
"label": "Clock Skew",
"help": "Number of msecs to skew the server clock by to test clock skew",
"placeholder": "0",
"default": "0",
"advanced": true
},
{
"name": "sendEnvironments",
"type": "checkbox",
"help": "send environmental data",
"default": false,
"advanced": true
},
{
"name": "minimalEnvironment",
"type": "checkbox",
"help": "send minimal environmental data if sending environmental data",
"default": false,
"advanced": true
}
]
}
]

View file

@ -1069,6 +1069,24 @@ void EntityTree::dumpTree() {
recurseTreeWithOperator(&theOperator);
}
class PruneOperator : public RecurseOctreeOperator {
public:
virtual bool preRecursion(OctreeElement* element) { return true; }
virtual bool postRecursion(OctreeElement* element);
};
bool PruneOperator::postRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
entityTreeElement->pruneChildren();
return true;
}
void EntityTree::pruneTree() {
// First, look for the existing entity in the tree..
PruneOperator theOperator;
recurseTreeWithOperator(&theOperator);
}
void EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z) {
SendEntitiesOperationArgs args;
args.packetSender = packetSender;

View file

@ -131,6 +131,7 @@ public:
void resetContainingElement(const EntityItemID& entityItemID, EntityTreeElement* element);
void debugDumpMap();
virtual void dumpTree();
virtual void pruneTree();
void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);

View file

@ -812,11 +812,20 @@ bool EntityTreeElement::pruneChildren() {
void EntityTreeElement::debugDump() {
qDebug() << "EntityTreeElement...";
qDebug() << "entity count:" << _entityItems->size();
qDebug() << "cube:" << getAACube();
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entity->debugDump();
AACube temp = getAACube();
temp.scale((float)TREE_SCALE);
qDebug() << " cube:" << temp;
qDebug() << " has child elements:" << getChildCount();
if (_entityItems->size()) {
qDebug() << " has entities:" << _entityItems->size();
qDebug() << "--------------------------------------------------";
for (uint16_t i = 0; i < _entityItems->size(); i++) {
EntityItem* entity = (*_entityItems)[i];
entity->debugDump();
}
qDebug() << "--------------------------------------------------";
} else {
qDebug() << " NO entities!";
}
}

View file

@ -352,6 +352,7 @@ public:
void setIsClient(bool isClient) { _isServer = !isClient; }
virtual void dumpTree() { };
virtual void pruneTree() { };
signals:
void importSize(float x, float y, float z);

View file

@ -246,9 +246,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch
// But we can't really do that with a packed message, since each edit message could be destined
// for a different server... So we need to actually manage multiple queued packets... one
// for each server
_packetsQueueLock.lock();
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
// only send to the NodeTypes that are getMyNodeType()
if (node->getActiveSocket() && node->getType() == getMyNodeType()) {
@ -277,12 +275,12 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, unsigned ch
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
(packetBuffer._currentSize + length >= (size_t)_maxPacketSize)) {
releaseQueuedPacket(packetBuffer);
initializePacket(packetBuffer, type);
initializePacket(packetBuffer, type, node->getClockSkewUsec());
}
// If the buffer is empty and not correctly initialized for our type...
if (type != packetBuffer._currentType && packetBuffer._currentSize == 0) {
initializePacket(packetBuffer, type);
initializePacket(packetBuffer, type, node->getClockSkewUsec());
}
// This is really the first time we know which server/node this particular edit message
@ -330,14 +328,14 @@ void OctreeEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer)
_releaseQueuedPacketMutex.unlock();
}
void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PacketType type) {
void OctreeEditPacketSender::initializePacket(EditPacketBuffer& packetBuffer, PacketType type, int nodeClockSkew) {
packetBuffer._currentSize = populatePacketHeader(reinterpret_cast<char*>(&packetBuffer._currentBuffer[0]), type);
// skip over sequence number for now; will be packed when packet is ready to be sent out
packetBuffer._currentSize += sizeof(quint16);
// pack in timestamp
quint64 now = usecTimestampNow();
quint64 now = usecTimestampNow() + nodeClockSkew;
quint64* timeAt = (quint64*)&packetBuffer._currentBuffer[packetBuffer._currentSize];
*timeAt = now;
packetBuffer._currentSize += sizeof(quint64); // nudge past timestamp

View file

@ -101,7 +101,7 @@ protected:
void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost = 0);
void initializePacket(EditPacketBuffer& packetBuffer, PacketType type);
void initializePacket(EditPacketBuffer& packetBuffer, PacketType type, int nodeClockSkew);
void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
void processPreServerExistsPackets();

View file

@ -36,6 +36,7 @@ bool OctreePersistThread::process() {
{
PerformanceWarning warn(true, "Loading Octree File", true);
persistantFileRead = _tree->readFromSVOFile(_filename.toLocal8Bit().constData());
_tree->pruneTree();
}
_tree->unlock();
@ -80,10 +81,14 @@ bool OctreePersistThread::process() {
// check the dirty bit and persist here...
_lastCheck = usecTimestampNow();
if (_tree->isDirty()) {
qDebug() << "saving Octrees to file " << _filename << "...";
qDebug() << "pruning Octree before saving...";
_tree->pruneTree();
qDebug() << "DONE pruning Octree before saving...";
qDebug() << "saving Octree to file " << _filename << "...";
_tree->writeToSVOFile(_filename.toLocal8Bit().constData());
_tree->clearDirtyBit(); // tree is clean after saving
qDebug("DONE saving Octrees to file...");
qDebug("DONE saving Octree to file...");
}
}
}