1
0
Fork 0

MirrorPropWebSocket: improve node recycling

Adjust logic for node recycling so common patterns observed with
remote canvas work correctly (remove + add of same nodes).
This commit is contained in:
James Turner 2018-09-30 10:16:31 +01:00
parent d0017f3bec
commit 9723f26f23

View file

@ -35,6 +35,8 @@
#include <3rdparty/cjson/cJSON.h> #include <3rdparty/cjson/cJSON.h>
//#define MIRROR_DEBUG 1
namespace flightgear { namespace flightgear {
namespace http { namespace http {
@ -75,7 +77,7 @@ using std::string;
break; break;
default: default:
SG_LOG(SG_NETWORK, SG_INFO, "implement me!" << type); SG_LOG(SG_NETWORK, SG_DEV_ALERT, "MirrorPropTree PropertyValue : implement me!" << type);
break; break;
} }
} }
@ -115,19 +117,20 @@ using std::string;
}; };
struct RecentlyRemovedNode struct RemovedNode
{ {
RecentlyRemovedNode() { } RemovedNode(SGPropertyNode* node, unsigned int aId) :
RecentlyRemovedNode(SGPropertyNode* node, unsigned int aId) :
type(node->getType()),
path(node->getPath()), path(node->getPath()),
id(aId) id(aId)
{} {}
simgear::props::Type type = simgear::props::NONE;
std::string path; std::string path;
unsigned int id = 0; unsigned int id = 0;
bool operator==(const RemovedNode& other) const
{
return (path == other.path);
}
}; };
class MirrorTreeListener : public SGPropertyChangeListener class MirrorTreeListener : public SGPropertyChangeListener
@ -166,28 +169,40 @@ using std::string;
void recursiveAdd(SGPropertyNode* node) void recursiveAdd(SGPropertyNode* node)
{ {
const auto type = node->getType(); RemovedNode r(node, 0 /* id not actually used */);
const auto& path = node->getPath(); #if defined (MIRROR_DEBUG)
auto rrIt = std::find_if(recentlyRemoved.begin(), recentlyRemoved.end(), SG_LOG(SG_NETWORK, SG_INFO, "looking for RR:" << r.path);
[type, &path](const RecentlyRemovedNode& rr) #endif
{ return (type == rr.type) && (path == rr.path); }); auto rrIt = std::find(recentlyRemoved.begin(), recentlyRemoved.end(), r);
if (rrIt != recentlyRemoved.end()) { if (rrIt != recentlyRemoved.end()) {
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "recycling node:" << node->getPath());
#endif
const auto id = rrIt->id;
// recycle nodes which get thrashed from Nasal (deleted + re-created // recycle nodes which get thrashed from Nasal (deleted + re-created
// each time a Nasal timer fires) // each time a Nasal timer fires)
removedNodes.erase(rrIt->id); // don't remove it! removedNodes.erase(id); // don't remove it!
idHash.insert(std::make_pair(node, rrIt->id)); idHash.insert(std::make_pair(node, id));
changedNodes.insert(node);
// we can still do change compression here, but this also
// deals with type mutation when removing + re-adding with a
// different type
PropertyValue newVal(node);
if (!previousValues[id].equals(node, newVal)) {
previousValues[id] = newVal;
changedNodes.insert(node);
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "\tand will actually change" << node->getPath());
#endif
}
recentlyRemoved.erase(rrIt); recentlyRemoved.erase(rrIt);
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "recycling node:" << path);
#endif
return; return;
} }
#if defined (MIRROR_DEBUG) #if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "new node:" << path); SG_LOG(SG_NETWORK, SG_INFO, "new node:" << node->getPath());
#endif #endif
newNodes.insert(node); newNodes.insert(node);
int child = 0; int child = 0;
for (; child < node->nChildren(); ++child) { for (; child < node->nChildren(); ++child) {
recursiveAdd(node->getChild(child)); recursiveAdd(node->getChild(child));
@ -203,12 +218,17 @@ using std::string;
if (it != idHash.end()) { if (it != idHash.end()) {
removedNodes.insert(it->second); removedNodes.insert(it->second);
idHash.erase(it); idHash.erase(it);
// record so we can map removed+add of the same property into // record so we can map removed+add of the same property into
// a simple value change (this happens commonly with the canvas // a simple value change (this happens commonly with the canvas
// due to lazy Nasal scripting) // due to lazy Nasal scripting)
recentlyRemoved.emplace_back(child, it->second); recentlyRemoved.emplace_back(child, it->second);
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "adding RR:" << recentlyRemoved.back().path);
#endif
} }
#if defined (MIRROR_DEBUG)
SG_LOG(SG_NETWORK, SG_INFO, "saw remove of:" << child->getPath());
#endif
} }
void registerSubtree(SGPropertyNode* node) void registerSubtree(SGPropertyNode* node)
@ -339,7 +359,7 @@ using std::string;
/// track recently removed nodes in case they are re-created imemdiately /// track recently removed nodes in case they are re-created imemdiately
/// after with the same type, since we can make this much more efficient /// after with the same type, since we can make this much more efficient
/// when sending over the wire. /// when sending over the wire.
std::vector<RecentlyRemovedNode> recentlyRemoved; std::vector<RemovedNode> recentlyRemoved;
}; };
#if 0 #if 0