Merge pull request #14539 from Atlante45/fix/script-loading

Fix ESS scripts getting stuck on load
This commit is contained in:
Jeff Clinton 2018-12-07 12:07:44 -08:00 committed by GitHub
commit 998ec20854
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 0 additions and 118 deletions

View file

@ -2061,68 +2061,6 @@ bool ScriptEngine::hasEntityScriptDetails(const EntityItemID& entityID) const {
return _entityScripts.contains(entityID);
}
const static EntityItemID BAD_SCRIPT_UUID_PLACEHOLDER { "{20170224-dead-face-0000-cee000021114}" };
void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const EntityItemID& leaderID) {
QList<DeferredLoadEntity> retryLoads;
QMutableListIterator<DeferredLoadEntity> i(_deferredEntityLoads);
while (i.hasNext()) {
auto retry = i.next();
if (retry.entityScript == entityScript) {
retryLoads << retry;
i.remove();
}
}
foreach(DeferredLoadEntity retry, retryLoads) {
// check whether entity was since been deleted
EntityScriptDetails details;
if (!getEntityScriptDetails(retry.entityID, details)) {
qCDebug(scriptengine) << "processDeferredEntityLoads -- entity details gone (entity deleted?)"
<< retry.entityID;
continue;
}
// check whether entity has since been unloaded or otherwise errored-out
if (details.status != EntityScriptStatus::PENDING) {
qCDebug(scriptengine) << "processDeferredEntityLoads -- entity status no longer PENDING; "
<< retry.entityID << details.status;
continue;
}
// propagate leader's failure reasons to the pending entity
EntityScriptDetails leaderDetails;
{
QWriteLocker locker { &_entityScriptsLock };
leaderDetails = _entityScripts[leaderID];
}
if (leaderDetails.status != EntityScriptStatus::RUNNING) {
qCDebug(scriptengine) << QString("... pending load of %1 cancelled (leader: %2 status: %3)")
.arg(retry.entityID.toString()).arg(leaderID.toString()).arg(leaderDetails.status);
auto extraDetail = QString("\n(propagated from %1)").arg(leaderID.toString());
if (leaderDetails.status == EntityScriptStatus::ERROR_LOADING_SCRIPT ||
leaderDetails.status == EntityScriptStatus::ERROR_RUNNING_SCRIPT) {
// propagate same error so User doesn't have to hunt down stampede's leader
updateEntityScriptStatus(retry.entityID, leaderDetails.status, leaderDetails.errorInfo + extraDetail);
} else {
// the leader Entity somehow ended up in some other state (rapid-fire delete or unload could cause)
updateEntityScriptStatus(retry.entityID, EntityScriptStatus::ERROR_LOADING_SCRIPT,
"A previous Entity failed to load using this script URL; reload to try again." + extraDetail);
}
continue;
}
if (_occupiedScriptURLs.contains(retry.entityScript)) {
qCWarning(scriptengine) << "--- SHOULD NOT HAPPEN -- recursive call into processDeferredEntityLoads" << retry.entityScript;
continue;
}
// if we made it here then the leading entity was successful so proceed with normal load
loadEntityScript(retry.entityID, retry.entityScript, false);
}
}
void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadEntityScript",
@ -2147,40 +2085,6 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString&
updateEntityScriptStatus(entityID, EntityScriptStatus::PENDING, "...pending...");
}
// This "occupied" approach allows multiple Entities to boot from the same script URL while still taking
// full advantage of cacheable require modules. This only affects Entities literally coming in back-to-back
// before the first one has time to finish loading.
if (_occupiedScriptURLs.contains(entityScript)) {
auto currentEntityID = _occupiedScriptURLs[entityScript];
if (currentEntityID == BAD_SCRIPT_UUID_PLACEHOLDER) {
if (forceRedownload) {
// script was previously marked unusable, but we're reloading so reset it
_occupiedScriptURLs.remove(entityScript);
} else {
// since not reloading, assume that the exact same input would produce the exact same output again
// note: this state gets reset with "reload all scripts," leaving/returning to a Domain, clear cache, etc.
#ifdef DEBUG_ENTITY_STATES
qCDebug(scriptengine) << QString("loadEntityScript.cancelled entity: %1 (previous script failure)")
.arg(entityID.toString());
#endif
updateEntityScriptStatus(entityID, EntityScriptStatus::ERROR_LOADING_SCRIPT,
"A previous Entity failed to load using this script URL; reload to try again.");
return;
}
} else {
// another entity is busy loading from this script URL so wait for them to finish
#ifdef DEBUG_ENTITY_STATES
qCDebug(scriptengine) << QString("loadEntityScript.deferring[%0] entity: %1 (waiting on %2 )")
.arg(_deferredEntityLoads.size()).arg(entityID.toString()).arg(currentEntityID.toString());
#endif
_deferredEntityLoads.push_back({ entityID, entityScript });
return;
}
}
// the scriptURL slot is available; flag as in-use
_occupiedScriptURLs[entityScript] = entityID;
#ifdef DEBUG_ENTITY_STATES
{
EntityScriptDetails details;
@ -2223,10 +2127,6 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString&
qCDebug(scriptengine) << "loadEntityScript.contentAvailable -- aborting";
#endif
}
// recheck whether us since may have been set to BAD_SCRIPT_UUID_PLACEHOLDER in entityScriptContentAvailable
if (_occupiedScriptURLs.contains(entityScript) && _occupiedScriptURLs[entityScript] == entityID) {
_occupiedScriptURLs.remove(entityScript);
}
});
}, forceRedownload);
}
@ -2301,13 +2201,6 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
newDetails.errorInfo = errorInfo;
newDetails.status = status;
setEntityScriptDetails(entityID, newDetails);
#ifdef DEBUG_ENTITY_STATES
qCDebug(scriptengine) << "entityScriptContentAvailable -- flagging as BAD_SCRIPT_UUID_PLACEHOLDER";
#endif
// flag the original entityScript as unusuable
_occupiedScriptURLs[entityScript] = BAD_SCRIPT_UUID_PLACEHOLDER;
processDeferredEntityLoads(entityScript, entityID);
};
// NETWORK / FILESYSTEM ERRORS
@ -2441,9 +2334,6 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
callEntityScriptMethod(entityID, "preload");
emit entityScriptPreloadFinished(entityID);
_occupiedScriptURLs.remove(entityScript);
processDeferredEntityLoads(entityScript, entityID);
}
/**jsdoc
@ -2499,10 +2389,6 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR
}
stopAllTimersForEntityScript(entityID);
{
// FIXME: shouldn't have to do this here, but currently something seems to be firing unloads moments after firing initial load requests
processDeferredEntityLoads(scriptText, entityID);
}
}
}
@ -2532,7 +2418,6 @@ void ScriptEngine::unloadAllEntityScripts() {
_entityScripts.clear();
}
emit entityScriptDetailsUpdated();
_occupiedScriptURLs.clear();
#ifdef DEBUG_ENGINE_STATE
_debugDump(

View file

@ -747,7 +747,6 @@ protected:
void updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus& status, const QString& errorInfo = QString());
void setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details);
void setParentURL(const QString& parentURL) { _parentURL = parentURL; }
void processDeferredEntityLoads(const QString& entityScript, const EntityItemID& leaderID);
QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
void stopTimer(QTimer* timer);
@ -783,8 +782,6 @@ protected:
QSet<QUrl> _includedURLs;
mutable QReadWriteLock _entityScriptsLock { QReadWriteLock::Recursive };
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
QHash<QString, EntityItemID> _occupiedScriptURLs;
QList<DeferredLoadEntity> _deferredEntityLoads;
EntityScriptContentAvailableMap _contentAvailableQueue;
bool _isThreaded { false };