From 9539ae8b550b8a95b455c41e4e42925633ff0f70 Mon Sep 17 00:00:00 2001 From: Mike Sul Date: Fri, 6 Dec 2024 15:42:34 +0100 Subject: [PATCH] appengine: Optimize app fetch check If an app is successfully fetched and checked then mark it as "fetched" so the next time when the app fetch check is called, then no need to invoke the full blown check performed by `composectl`. Signed-off-by: Mike Sul --- src/composeapp/appengine.cc | 10 ++++++++++ src/composeapp/appengine.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/composeapp/appengine.cc b/src/composeapp/appengine.cc index 35eaae28..a6d94ec1 100644 --- a/src/composeapp/appengine.cc +++ b/src/composeapp/appengine.cc @@ -14,6 +14,9 @@ static bool checkAppStatus(const AppEngine::App& app, const Json::Value& status) AppEngine::Result AppEngine::fetch(const App& app) { Result res{false}; try { + // If a given app was fetched before, then don't consider it as a fetched app if a caller tries to fetch it again + // for one reason or another - hence remove it from the set of fetched apps. + fetched_apps_.erase(app.uri); if (local_source_path_.empty()) { exec(boost::format{"%s --store %s pull -p %s --storage-usage-watermark %d"} % composectl_cmd_ % storeRoot() % app.uri % storage_watermark_, @@ -24,6 +27,7 @@ AppEngine::Result AppEngine::fetch(const App& app) { "failed to pull compose app"); } res = true; + fetched_apps_.insert(app.uri); } catch (const ExecError& exc) { if (exc.ExitCode == static_cast(ExitCode::ExitCodeInsufficientSpace)) { const auto usage_stat{Utils::parseJSON(exc.StdErr)}; @@ -40,6 +44,7 @@ AppEngine::Result AppEngine::fetch(const App& app) { void AppEngine::remove(const App& app) { try { + fetched_apps_.erase(app.uri); // "App removal" in this context refers to deleting app images from the Docker store // and removing the app compose project (app uninstall). // Unused app blobs will be removed from the blob store via the prune() method, @@ -114,6 +119,7 @@ void AppEngine::prune(const Apps& app_shortlist) { } } for (const auto& app : apps_to_prune) { + fetched_apps_.erase(app.uri); exec(boost::format{"%s --store %s rm %s --prune=false --quiet"} % composectl_cmd_ % storeRoot() % app.uri, "failed to remove app"); } @@ -143,6 +149,9 @@ void AppEngine::prune(const Apps& app_shortlist) { bool AppEngine::isAppFetched(const App& app) const { bool res{false}; + if (fetched_apps_.count(app.uri) > 0) { + return true; + } try { std::future output; exec(boost::format{"%s --store %s check %s --local --format json"} % composectl_cmd_ % storeRoot() % app.uri, "", @@ -152,6 +161,7 @@ bool AppEngine::isAppFetched(const App& app) const { if (app_fetch_status.isMember("fetch_check") && app_fetch_status["fetch_check"].isMember("missing_blobs") && app_fetch_status["fetch_check"]["missing_blobs"].empty()) { res = true; + fetched_apps_.insert(app.uri); } } catch (const ExecError& exc) { LOG_DEBUG << "app is not fully fetched; app: " << app.name << ", status: " << exc.what(); diff --git a/src/composeapp/appengine.h b/src/composeapp/appengine.h index cb1043c7..0fde4a42 100644 --- a/src/composeapp/appengine.h +++ b/src/composeapp/appengine.h @@ -37,6 +37,7 @@ class AppEngine : public Docker::RestorableAppEngine { const std::string composectl_cmd_; const int storage_watermark_; const std::string local_source_path_; + mutable std::set fetched_apps_; }; } // namespace composeapp