Skip to content

Commit

Permalink
Avoid reinstalling installonly packages marked for ERASE
Browse files Browse the repository at this point in the history
Without this patch reinstalling installonly pkg marked for ERASE might
be a valid smallest solution to our job.

For example when user wants to install through a provide we select all
packages that provide it and put them inside a `job install oneof ...`
if one of the providers is also marked for ERASE due to installonly
limit libsolv might decide to reinstall it.

To make sure it doesn't happen mark the available package also as ERASE.

openSUSE/libsolv#540

https://bugzilla.redhat.com/show_bug.cgi?id=2163474
https://issues.redhat.com/browse/RHEL-1253
  • Loading branch information
kontura authored and j-mracek committed Oct 17, 2023
1 parent 9af6bc2 commit dab978c
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions libdnf5/rpm/solv/goal_private.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "goal_private.hpp"

#include "rpm/package_sack_impl.hpp"
#include "solv/pool.hpp"

#include "libdnf5/common/exception.hpp"
Expand Down Expand Up @@ -223,6 +224,9 @@ int obsq_cmp(const Id * ap, const Id * bp, const ObsoleteCmpData * s_cb) {
return *ap - *bp;
}

inline bool name_solvable_cmp_key(const Solvable * first, const Solvable * second) {
return first->name < second->name;
}

} // namespace

Expand All @@ -243,14 +247,27 @@ bool GoalPrivate::limit_installonly_packages(libdnf5::solv::IdQueue & job, Id ru
Id p;
Id pp;
libdnf5::solv::IdQueue q;
std::vector<Solvable *> available_unused_providers;
libdnf5::solv::IdQueue installing;

// Add all providers of installonly provides that are marked for install
// to `q` IdQueue those that are not marked for install and are not already
// installed are added to available_unused_providers.
FOR_PROVIDES(p, pp, installonly[i]) {
// TODO(jmracek) Replase the test by cached data from sack.p_impl->get_solvables()
if (!spool.is_package(p)) {
continue;
}
// According to libsolv-bindings the decision level is positive for installs
// and negative for conflicts (conflicts with another package or dependency
// conflicts = dependencies cannot be met).
if (libsolv_solver.get_decisionlevel(p) > 0) {
q.push_back(p);
} else {
Solvable * solvable = spool.id2solvable(p);
if (!spool.is_installed(solvable)) {
available_unused_providers.push_back(solvable);
}
}
}
if (q.size() <= static_cast<int>(installonly_limit)) {
Expand All @@ -270,6 +287,7 @@ bool GoalPrivate::limit_installonly_packages(libdnf5::solv::IdQueue & job, Id ru

const InstallonlyCmpData installonly_cmp_data{spool, running_kernel};
q.sort(&installonly_cmp, &installonly_cmp_data);
std::sort(available_unused_providers.begin(), available_unused_providers.end(), name_solvable_cmp_key);

libdnf5::solv::IdQueue same_names;
while (q.size() > 0) {
Expand All @@ -283,6 +301,19 @@ bool GoalPrivate::limit_installonly_packages(libdnf5::solv::IdQueue & job, Id ru
Id action = SOLVER_ERASE;
if (j < static_cast<int>(installonly_limit)) {
action = SOLVER_INSTALL;
} else {
// We want to avoid reinstalling packages marked for ERASE, therefore
// if some unused provider is also available we need to mark it ERASE as well.
Solvable * solvable = spool.id2solvable(id);
auto low = std::lower_bound(
available_unused_providers.begin(),
available_unused_providers.end(),
solvable,
nevra_solvable_cmp_key);
while (low != available_unused_providers.end() && (*low)->name == solvable->name) {
job.push_back(SOLVER_ERASE | SOLVER_SOLVABLE, spool.solvable2id(*low));
++low;
}
}
job.push_back(action | SOLVER_SOLVABLE, id);
}
Expand Down

0 comments on commit dab978c

Please sign in to comment.