Commit 2d6f6522 authored by Gigg, Martyn Anthony's avatar Gigg, Martyn Anthony
Browse files

Clean up internal workspace caches within an Algorithm object

The algorithm object should only store a reference to any input
workspaces if it is told not to store in the ADS and then it
should only have a single reference by the time execution has
completed. Here we clean out internal caches of workspace pointers
that were keeping workspaces alive if an algorithm object was not
removed immediately, e.g. in the AlgorithmManager.

The AlgorithmProxy used ensure this happend after algorithm execution
finished but that no longer exists. Some workspace types require workspace
destruction to release resources such as file locks, e.g file-backed
MDWorkspaces, and keeping references to those workspaces complicates
writing scripts a subsequent operation required a workspace to be
deleted.
parent 16969e53
......@@ -416,8 +416,11 @@ private:
void doSetInputProperties(const std::string &name, const T1 &wksp,
IndexType type, const T2 &list);
void lockWorkspaces();
void unlockWorkspaces();
void clearWorkspaceCaches();
void linkHistoryWithLastChild();
void logAlgorithmInfo() const;
......
......@@ -67,6 +67,16 @@ public:
private:
const std::string &m_value;
};
template <typename T> struct RunOnFinish {
RunOnFinish(T &&task) : m_onfinsh(std::move(task)) {}
~RunOnFinish() { m_onfinsh(); }
private:
T m_onfinsh;
};
} // namespace
// Doxygen can't handle member specialization at the moment:
......@@ -511,6 +521,19 @@ void Algorithm::unlockWorkspaces() {
m_writeLockedWorkspaces.clear();
}
/**
* Clear any internal workspace handles so that workspaces will be deleted
* promptly after a managed algorithm finishes
*/
void Algorithm::clearWorkspaceCaches() {
m_groupWorkspaces.clear();
m_inputWorkspaceHistories.clear();
m_inputWorkspaceProps.clear();
m_outputWorkspaceProps.clear();
m_pureOutputWorkspaceProps.clear();
m_unrolledInputWorkspaces.clear();
}
//---------------------------------------------------------------------------------------------
/** Invoced internally in execute()
*/
......@@ -525,6 +548,11 @@ bool Algorithm::executeInternal() {
getLogger().error(depo->deprecationMsg(this));
}
// Register clean up tasks that should happen regardless of the route
// out of the algorithm. These tasks will get run after this method
// finishes.
RunOnFinish onFinish([this]() { this->clearWorkspaceCaches(); });
notificationCenter().postNotification(new StartedNotification(this));
Mantid::Types::Core::DateAndTime startTime;
......@@ -707,7 +735,6 @@ bool Algorithm::executeInternal() {
new ErrorNotification(this, ex.what()));
setResultState(ResultState::Failed);
this->unlockWorkspaces();
if (m_isChildAlgorithm || m_runningAsync || m_rethrow)
throw;
else {
......@@ -740,6 +767,7 @@ bool Algorithm::executeInternal() {
notificationCenter().postNotification(
new ErrorNotification(this, ex.what()));
this->unlockWorkspaces();
throw;
}
......@@ -755,10 +783,10 @@ bool Algorithm::executeInternal() {
getLogger().error() << this->name()
<< ": UNKNOWN Exception is caught in exec()\n";
this->unlockWorkspaces();
throw;
}
// Unlock the locked workspaces
this->unlockWorkspaces();
m_gcTime = Mantid::Types::Core::DateAndTime::getCurrentTime() +=
......
......@@ -578,6 +578,53 @@ public:
}
}
void test_Algorithm_Drops_Workspace_References_When_Stored_In_ADS() {
// create an input workspace, add it to the ADS
auto inputWorkspace = std::make_shared<WorkspaceTester>();
const std::string inputName("testIn"), outputName("testOut");
auto &ads = AnalysisDataService::Instance();
ads.addOrReplace(inputName, inputWorkspace);
auto workspaceAlg = std::make_unique<StubbedWorkspaceAlgorithm>();
workspaceAlg->initialize();
workspaceAlg->setProperty("InputWorkspace1", inputName);
workspaceAlg->setProperty("OutputWorkspace1", outputName);
workspaceAlg->execute();
// The input workspace should have references from the local inputWorkspace
// variable and in the ADS but nothing else
TS_ASSERT_EQUALS(2, inputWorkspace.use_count());
// dropping algorithm shouldn't alter the use count
workspaceAlg.reset();
TS_ASSERT_EQUALS(2, inputWorkspace.use_count());
// drop ADS reference and left with local
ads.remove(inputName);
TS_ASSERT_EQUALS(1, inputWorkspace.use_count());
}
void test_Algorithm_Keeps_Only_WorkspaceProperty_Ref_If_Not_Stored_In_ADS() {
// create an input workspace, add it to the ADS
auto inputWorkspace = std::make_shared<WorkspaceTester>();
const std::string inputName("testIn"), outputName("testOut");
auto workspaceAlg = std::make_unique<StubbedWorkspaceAlgorithm>();
workspaceAlg->initialize();
workspaceAlg->setAlwaysStoreInADS(false);
workspaceAlg->setProperty("InputWorkspace1", inputWorkspace);
workspaceAlg->setProperty("OutputWorkspace1", outputName);
workspaceAlg->execute();
// The input workspace should have references from the algorithm
// and the local variable
TS_ASSERT_EQUALS(2, inputWorkspace.use_count());
// dropping algorithm should leave the local variable
workspaceAlg.reset();
TS_ASSERT_EQUALS(1, inputWorkspace.use_count());
}
//------------------------------------------------------------------------
/** Make a workspace group with:
*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment