diff --git a/librepomgr/buildactions/buildaction.cpp b/librepomgr/buildactions/buildaction.cpp index a696455..e490255 100644 --- a/librepomgr/buildactions/buildaction.cpp +++ b/librepomgr/buildactions/buildaction.cpp @@ -323,6 +323,9 @@ LibPkg::StorageID BuildAction::start(ServiceSetup &setup, std::unique_ptr(); break; + case BuildActionType::BuildServiceCleanup: + post(); + break; default: resultData = "not implemented yet or invalid type"; return conclude(BuildActionResult::Failure); @@ -409,6 +412,43 @@ LibPkg::StorageID BuildAction::conclude(BuildActionResult result) return id; } +BuildServiceCleanup::BuildServiceCleanup(ServiceSetup &setup, const std::shared_ptr &buildAction) + : InternalBuildAction(setup, buildAction) +{ +} + +void BuildServiceCleanup::run() +{ + // validate parameter + if (auto error = validateParameter(RequiredDatabases::None, RequiredParameters::None); !error.empty()) { + reportError(move(error)); + return; + } + + // iterate though build actions and delete those that are unlikely to be relevant anymore + auto count = std::size_t(); + constexpr auto stopAt = 150; + m_setup.building.forEachBuildAction( + [this, &count, twoWeeksAgo = DateTime::gmtNow() - TimeSpan::fromDays(14)]( + LibPkg::StorageID id, BuildAction &action, ServiceSetup::BuildSetup::VisitorBehavior &visitorBehavior) { + if (count <= stopAt) { + return true; // abort deletion if under 150 build actions anyways + } + if (m_buildAction->id == id || action.finished.isNull()) { + return false; // avoid deleting cleanup action itself as well as any unfinished actions + } + if (action.result != BuildActionResult::Success || action.finished > twoWeeksAgo) { + return false; // delete only successful actions that are at least two weeks old + } + visitorBehavior = ServiceSetup::BuildSetup::VisitorBehavior::Delete; + return --count <= stopAt; + }, + &count); + + const auto buildActionLock = m_setup.building.lockToWrite(); + reportSuccess(); +} + #ifdef LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED DummyBuildAction::DummyBuildAction(ServiceSetup &setup, const std::shared_ptr &buildAction) : InternalBuildAction(setup, buildAction) diff --git a/librepomgr/buildactions/buildactionmeta.cpp b/librepomgr/buildactions/buildactionmeta.cpp index 8e713cc..fda30b6 100644 --- a/librepomgr/buildactions/buildactionmeta.cpp +++ b/librepomgr/buildactions/buildactionmeta.cpp @@ -373,6 +373,18 @@ BuildActionMetaInfo::BuildActionMetaInfo() .destinationDb = false, .packageNames = false, }, + BuildActionTypeMetaInfo{ + .id = BuildActionType::BuildServiceCleanup, + .category = "Misc", + .name = "Clean build-service-internal data", + .type = "build-service-cleanup", + .flags = {}, + .settings = {}, + .directory = false, + .sourceDb = false, + .destinationDb = false, + .packageNames = false, + }, }) , states({ BuildActionStatusMetaInfo{ diff --git a/librepomgr/buildactions/buildactionmeta.h b/librepomgr/buildactions/buildactionmeta.h index e8eefea..80cc387 100644 --- a/librepomgr/buildactions/buildactionmeta.h +++ b/librepomgr/buildactions/buildactionmeta.h @@ -47,7 +47,8 @@ enum class BuildActionType : std::uint64_t { CleanRepository, DummyBuildAction, CustomCommand, - LastType = CustomCommand, + BuildServiceCleanup, + LastType = BuildServiceCleanup, }; using BuildActionFlagType = std::uint64_t; diff --git a/librepomgr/buildactions/buildactionprivate.h b/librepomgr/buildactions/buildactionprivate.h index b68893e..017efa2 100644 --- a/librepomgr/buildactions/buildactionprivate.h +++ b/librepomgr/buildactions/buildactionprivate.h @@ -656,6 +656,13 @@ private: bool m_useContainer; }; +struct LIBREPOMGR_EXPORT BuildServiceCleanup : public InternalBuildAction { + BuildServiceCleanup(ServiceSetup &setup, const std::shared_ptr &buildAction); + void run(); + +private: +}; + #ifdef LIBREPOMGR_DUMMY_BUILD_ACTION_ENABLED struct LIBREPOMGR_EXPORT DummyBuildAction : public InternalBuildAction { DummyBuildAction(ServiceSetup &setup, const std::shared_ptr &buildAction); diff --git a/librepomgr/serversetup.cpp b/librepomgr/serversetup.cpp index 09418b8..20296dd 100644 --- a/librepomgr/serversetup.cpp +++ b/librepomgr/serversetup.cpp @@ -417,22 +417,30 @@ void ServiceSetup::BuildSetup::forEachBuildAction( } } -void ServiceSetup::BuildSetup::forEachBuildAction(ServiceSetup::BuildSetup::BuildActionVisitorWriteable &&func) +void ServiceSetup::BuildSetup::forEachBuildAction(ServiceSetup::BuildSetup::BuildActionVisitorWriteable &&func, std::size_t *count) { auto txn = m_storage->buildActions.getRWTransaction(); + if (count) { + *count = txn.size(); + } for (auto i = txn.begin(); i != txn.end(); ++i) { const auto running = m_runningActions.find(i.getID()); auto &action = running != m_runningActions.end() ? *running->second : i.value(); - auto save = false; - const auto stop = func(i.getID(), action, save); - if (save) { + auto visitorBehavior = VisitorBehavior::DiscardChanges; + const auto stop = func(i.getID(), action, visitorBehavior); + if (visitorBehavior == VisitorBehavior::SaveChanges) { if (running != m_runningActions.end() && !action.isExecuting()) { m_runningActions.erase(running); } txn.put(action, i.getID()); + } else if (visitorBehavior == VisitorBehavior::Delete && !action.isExecuting()) { + if (running != m_runningActions.end()) { + m_runningActions.erase(running); + } + txn.del(i.getID()); } if (stop) { - return; + break; } } txn.commit(); @@ -713,12 +721,12 @@ void ServiceSetup::restoreState() building.initStorage(building.dbPath.data()); // ensure no build actions are considered running anymore and populate follow up actions - building.forEachBuildAction([this](LibPkg::StorageID, BuildAction &buildAction, bool &save) { + building.forEachBuildAction([this](LibPkg::StorageID, BuildAction &buildAction, BuildSetup::VisitorBehavior &visitorBehavior) { if (buildAction.isExecuting()) { buildAction.status = BuildActionStatus::Finished; buildAction.result = BuildActionResult::Failure; buildAction.resultData = "service crashed while exectuing"; - save = true; + visitorBehavior = BuildSetup::VisitorBehavior::SaveChanges; } else if (buildAction.isScheduled()) { for (const auto previousBuildActionId : buildAction.startAfter) { building.m_followUpActions[previousBuildActionId].emplace(buildAction.id); @@ -809,11 +817,11 @@ int ServiceSetup::run() try { #endif saveState(); - building.forEachBuildAction([](LibPkg::StorageID, BuildAction &buildAction, bool &save) { + building.forEachBuildAction([](LibPkg::StorageID, BuildAction &buildAction, BuildSetup::VisitorBehavior &visitorBehavior) { if (buildAction.isExecuting()) { buildAction.status = BuildActionStatus::Finished; buildAction.result = BuildActionResult::Aborted; - save = true; + visitorBehavior = BuildSetup::VisitorBehavior::SaveChanges; } return false; }); diff --git a/librepomgr/serversetup.h b/librepomgr/serversetup.h index 1e03a50..01e508b 100644 --- a/librepomgr/serversetup.h +++ b/librepomgr/serversetup.h @@ -92,6 +92,12 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { BuildSetup &setup; }; + enum class VisitorBehavior { + DiscardChanges, + SaveChanges, + Delete, + }; + explicit BuildSetup(); BuildSetup(BuildSetup &&) = delete; ~BuildSetup(); @@ -148,8 +154,8 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable { void rebuildDb(); using BuildActionVisitorBase = std::function; void forEachBuildAction(std::function count, BuildActionVisitorBase &&func, std::size_t limit, std::size_t start); - using BuildActionVisitorWriteable = std::function; - void forEachBuildAction(BuildActionVisitorWriteable &&func); + using BuildActionVisitorWriteable = std::function; + void forEachBuildAction(BuildActionVisitorWriteable &&func, std::size_t *count = nullptr); std::vector> followUpBuildActions(BuildActionIdType forId); private: