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://issues.redhat.com/browse/RHEL-1253
(https://bugzilla.redhat.com/show_bug.cgi?id=2163474)
  • Loading branch information
kontura authored and j-mracek committed Oct 3, 2023
1 parent 933f00f commit 4b016ce
Showing 1 changed file with 33 additions and 2 deletions.
35 changes: 33 additions & 2 deletions libdnf/goal/Goal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,12 @@ erase_flags2libsolv(int flags)
return ret;
}

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

Goal::Goal(const Goal & goal_src) : pImpl(new Impl(*goal_src.pImpl)) {}

Goal::Impl::Impl(const Goal::Impl & goal_src)
Expand Down Expand Up @@ -1436,10 +1442,24 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
for (int i = 0; i < onlies->count; ++i) {
Id p, pp;
IdQueue q, installing;
std::vector<Solvable *> available_unused_providers;

// 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_PKG_PROVIDES(p, pp, onlies->elements[i])
if (solver_get_decisionlevel(solv, p) > 0)
// 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 (solver_get_decisionlevel(solv, p) > 0) {
q.pushBack(p);
} else {
Solvable *s = pool_id2solvable(pool, p);
if (s->repo != pool->installed) {
available_unused_providers.push_back(s);
}
}

if (q.size() <= (int) dnf_sack_get_installonly_limit(sack)) {
continue;
}
Expand All @@ -1457,6 +1477,7 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)

struct InstallonliesSortCallback s_cb = {pool, dnf_sack_running_kernel(sack)};
solv_sort(q.data(), q.size(), sizeof(q[0]), sort_packages, &s_cb);
std::sort(available_unused_providers.begin(), available_unused_providers.end(), NameSolvableComparator);
IdQueue same_names;
while (q.size() > 0) {
same_name_subqueue(pool, q.getQueue(), same_names.getQueue());
Expand All @@ -1466,8 +1487,18 @@ Goal::Impl::limitInstallonlyPackages(Solver *solv, Queue *job)
for (int j = 0; j < same_names.size(); ++j) {
Id id = same_names[j];
Id action = SOLVER_ERASE;
if (j < (int) dnf_sack_get_installonly_limit(sack))
if (j < (int) dnf_sack_get_installonly_limit(sack)) {
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 *s = pool_id2solvable(pool, id);
auto low = std::lower_bound(available_unused_providers.begin(), available_unused_providers.end(), s, NameSolvableComparator);
while (low != available_unused_providers.end() && (*low)->name == s->name) {
queue_push2(job, SOLVER_ERASE | SOLVER_SOLVABLE, pool_solvable2id(pool, *low));
++low;
}
}
queue_push2(job, action | SOLVER_SOLVABLE, id);
}
}
Expand Down

0 comments on commit 4b016ce

Please sign in to comment.