Use async locks when invoking custom command
This commit is contained in:
parent
80b5094659
commit
599185d3ae
|
@ -381,7 +381,16 @@ struct LIBREPOMGR_EXPORT CustomCommand : public InternalBuildAction {
|
|||
void run();
|
||||
|
||||
private:
|
||||
void acquireNextSharedLock();
|
||||
void acquireNextExclusiveLock();
|
||||
|
||||
std::string m_workingDirectory;
|
||||
const std::string *m_command;
|
||||
std::shared_ptr<BuildProcessSession> m_process;
|
||||
std::set<std::string_view> m_sharedLockNames;
|
||||
std::set<std::string_view> m_exclusiveLockNames;
|
||||
std::set<std::string_view>::iterator m_sharedLockNamesIterator;
|
||||
std::set<std::string_view>::iterator m_exclusiveLockNamesIterator;
|
||||
};
|
||||
|
||||
struct LIBREPOMGR_EXPORT ReloadDatabase : public InternalBuildAction {
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace LibRepoMgr {
|
|||
|
||||
CustomCommand::CustomCommand(ServiceSetup &setup, const std::shared_ptr<BuildAction> &buildAction)
|
||||
: InternalBuildAction(setup, buildAction)
|
||||
, m_command(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -57,43 +58,73 @@ void CustomCommand::run()
|
|||
m_buildAction->appendOutput(Phrases::InfoMessage, "Running custom command: ", command, '\n');
|
||||
|
||||
// prepare process and finish handler
|
||||
auto process
|
||||
= m_buildAction->makeBuildProcess("command", m_workingDirectory + "/the.log", [this](boost::process::child &&, ProcessResult &&result) {
|
||||
if (result.errorCode) {
|
||||
m_buildAction->appendOutput(Phrases::InfoMessage, "Unable to invoke command: ", result.errorCode.message());
|
||||
reportError(result.errorCode.message());
|
||||
return;
|
||||
}
|
||||
m_buildAction->appendOutput(
|
||||
result.exitCode == 0 ? Phrases::InfoMessage : Phrases::ErrorMessage, "Command exited with return code ", result.exitCode);
|
||||
if (result.exitCode != 0) {
|
||||
reportError(argsToString("non-zero exit code ", result.exitCode));
|
||||
return;
|
||||
}
|
||||
const auto buildLock = m_setup.building.lockToWrite();
|
||||
reportSuccess();
|
||||
});
|
||||
m_command = &command;
|
||||
m_process = m_buildAction->makeBuildProcess("command", m_workingDirectory + "/the.log", [this](boost::process::child &&, ProcessResult &&result) {
|
||||
if (result.errorCode) {
|
||||
m_buildAction->appendOutput(Phrases::InfoMessage, "Unable to invoke command: ", result.errorCode.message());
|
||||
reportError(result.errorCode.message());
|
||||
return;
|
||||
}
|
||||
m_buildAction->appendOutput(
|
||||
result.exitCode == 0 ? Phrases::InfoMessage : Phrases::ErrorMessage, "Command exited with return code ", result.exitCode);
|
||||
if (result.exitCode != 0) {
|
||||
reportError(argsToString("non-zero exit code ", result.exitCode));
|
||||
return;
|
||||
}
|
||||
const auto buildLock = m_setup.building.lockToWrite();
|
||||
reportSuccess();
|
||||
});
|
||||
|
||||
// acquire locks
|
||||
// note: Using an std::set here (instead of a std::vector) to ensure we don't attempt to acquire the same lock twice and to ensure
|
||||
// locks are always acquired in the same order (to prevent deadlocks).
|
||||
const auto sharedLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(sharedLocksSetting), ",");
|
||||
const auto exclusiveLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(exclusiveLocksSetting), ",");
|
||||
auto &locks = process->locks();
|
||||
auto &log = m_buildAction->log();
|
||||
locks.reserve(sharedLockNames.size() + exclusiveLockNames.size());
|
||||
for (const auto &lockName : sharedLockNames) {
|
||||
if (!lockName.empty()) {
|
||||
locks.emplace_back(m_setup.locks.acquireToRead(log, std::string(lockName)));
|
||||
}
|
||||
}
|
||||
for (const auto &lockName : exclusiveLockNames) {
|
||||
if (!lockName.empty()) {
|
||||
locks.emplace_back(m_setup.locks.acquireToWrite(log, std::string(lockName)));
|
||||
}
|
||||
}
|
||||
m_sharedLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(sharedLocksSetting), ",");
|
||||
m_sharedLockNamesIterator = m_sharedLockNames.begin();
|
||||
m_exclusiveLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(exclusiveLocksSetting), ",");
|
||||
m_exclusiveLockNamesIterator = m_exclusiveLockNames.begin();
|
||||
m_process->locks().reserve(m_sharedLockNames.size() + m_exclusiveLockNames.size());
|
||||
acquireNextSharedLock();
|
||||
}
|
||||
|
||||
process->launch(boost::process::start_dir(m_workingDirectory), boost::process::search_path("bash"), "-ec", command);
|
||||
void LibRepoMgr::CustomCommand::acquireNextSharedLock()
|
||||
{
|
||||
if (m_sharedLockNamesIterator == m_sharedLockNames.end()) {
|
||||
// continue acquiring exclusive locks once all shared locks are acquired
|
||||
acquireNextExclusiveLock();
|
||||
return;
|
||||
}
|
||||
if (m_sharedLockNamesIterator->empty()) {
|
||||
++m_sharedLockNamesIterator;
|
||||
acquireNextSharedLock();
|
||||
return;
|
||||
}
|
||||
m_setup.locks.acquireToRead(
|
||||
m_buildAction->log(), std::string(*m_sharedLockNamesIterator), [this, buildAction = m_buildAction](SharedLoggingLock &&lock) {
|
||||
m_process->locks().emplace_back(std::move(lock));
|
||||
++m_sharedLockNamesIterator;
|
||||
acquireNextSharedLock();
|
||||
});
|
||||
}
|
||||
|
||||
void LibRepoMgr::CustomCommand::acquireNextExclusiveLock()
|
||||
{
|
||||
if (m_exclusiveLockNamesIterator == m_exclusiveLockNames.end()) {
|
||||
// execute process once all locks are acquired
|
||||
m_process->launch(boost::process::start_dir(m_workingDirectory), boost::process::search_path("bash"), "-ec", *m_command);
|
||||
m_process.reset();
|
||||
return;
|
||||
}
|
||||
if (m_exclusiveLockNamesIterator->empty()) {
|
||||
++m_exclusiveLockNamesIterator;
|
||||
acquireNextExclusiveLock();
|
||||
return;
|
||||
}
|
||||
m_setup.locks.acquireToWrite(
|
||||
m_buildAction->log(), std::string(*m_exclusiveLockNamesIterator), [this, buildAction = m_buildAction](UniqueLoggingLock &&lock) {
|
||||
m_process->locks().emplace_back(std::move(lock));
|
||||
++m_exclusiveLockNamesIterator;
|
||||
acquireNextExclusiveLock();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace LibRepoMgr
|
||||
|
|
Loading…
Reference in New Issue