Use async locks when invoking custom command

This commit is contained in:
Martchus 2023-01-17 22:58:03 +01:00
parent 80b5094659
commit 599185d3ae
2 changed files with 72 additions and 32 deletions

View File

@ -381,7 +381,16 @@ struct LIBREPOMGR_EXPORT CustomCommand : public InternalBuildAction {
void run(); void run();
private: private:
void acquireNextSharedLock();
void acquireNextExclusiveLock();
std::string m_workingDirectory; 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 { struct LIBREPOMGR_EXPORT ReloadDatabase : public InternalBuildAction {

View File

@ -16,6 +16,7 @@ namespace LibRepoMgr {
CustomCommand::CustomCommand(ServiceSetup &setup, const std::shared_ptr<BuildAction> &buildAction) CustomCommand::CustomCommand(ServiceSetup &setup, const std::shared_ptr<BuildAction> &buildAction)
: InternalBuildAction(setup, buildAction) : InternalBuildAction(setup, buildAction)
, m_command(nullptr)
{ {
} }
@ -57,8 +58,8 @@ void CustomCommand::run()
m_buildAction->appendOutput(Phrases::InfoMessage, "Running custom command: ", command, '\n'); m_buildAction->appendOutput(Phrases::InfoMessage, "Running custom command: ", command, '\n');
// prepare process and finish handler // prepare process and finish handler
auto process m_command = &command;
= m_buildAction->makeBuildProcess("command", m_workingDirectory + "/the.log", [this](boost::process::child &&, ProcessResult &&result) { m_process = m_buildAction->makeBuildProcess("command", m_workingDirectory + "/the.log", [this](boost::process::child &&, ProcessResult &&result) {
if (result.errorCode) { if (result.errorCode) {
m_buildAction->appendOutput(Phrases::InfoMessage, "Unable to invoke command: ", result.errorCode.message()); m_buildAction->appendOutput(Phrases::InfoMessage, "Unable to invoke command: ", result.errorCode.message());
reportError(result.errorCode.message()); reportError(result.errorCode.message());
@ -77,23 +78,53 @@ void CustomCommand::run()
// acquire locks // 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 // 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). // locks are always acquired in the same order (to prevent deadlocks).
const auto sharedLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(sharedLocksSetting), ","); m_sharedLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(sharedLocksSetting), ",");
const auto exclusiveLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(exclusiveLocksSetting), ","); m_sharedLockNamesIterator = m_sharedLockNames.begin();
auto &locks = process->locks(); m_exclusiveLockNames = splitStringSimple<std::set<std::string_view>>(findSetting(exclusiveLocksSetting), ",");
auto &log = m_buildAction->log(); m_exclusiveLockNamesIterator = m_exclusiveLockNames.begin();
locks.reserve(sharedLockNames.size() + exclusiveLockNames.size()); m_process->locks().reserve(m_sharedLockNames.size() + m_exclusiveLockNames.size());
for (const auto &lockName : sharedLockNames) { acquireNextSharedLock();
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)));
}
} }
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 } // namespace LibRepoMgr