From 8c13d9cb1c38ebb52cf6e1c8c7561c5c5d87c970 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 2 Jul 2024 18:51:11 +0200 Subject: solver3: Consider packages as obsolete and not versions This makes more sense, as all package versions are obsolete that are not the candidate, usually. Pay special attention to no-strict-pinning: If we don't have strict pinning, a package without a candidate version may still be non-obsolete if the latest version is not obsolete. Likewise, in no-strict-pinning any later source version that exists will cause the package to be considered obsolete, rather than just candidates. --- apt-pkg/solver3.cc | 35 ++++++++++++++++++++++++----------- apt-pkg/solver3.h | 4 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 7580d6e18..29bd3a115 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -64,8 +64,8 @@ struct APT::Solver::CompareProviders3 /*{{{*/ // Try obsolete choices only after exhausting non-obsolete choices such that we install // packages replacing them and don't keep back upgrades depending on the replacement to // keep the obsolete package installed. - if (auto obsoleteAV = Solver.Obsolete(AV), obsoleteBV = Solver.Obsolete(BV); obsoleteAV != obsoleteBV) - return obsoleteBV; + if (auto obsoleteA = Solver.Obsolete(A), obsoleteB = Solver.Obsolete(B); obsoleteA != obsoleteB) + return obsoleteB; // Prefer MA:same packages if other architectures for it are installed if ((AV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same || (BV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) @@ -166,7 +166,7 @@ APT::Solver::Solver(pkgCache &cache, pkgDepCache::Policy &policy) policy(policy), pkgStates(cache.Head().PackageCount), verStates(cache.Head().VersionCount), - verObsolete(cache.Head().VersionCount) + pkgObsolete(cache.Head().PackageCount) { static_assert(sizeof(APT::Solver::State) == 3 * sizeof(int)); static_assert(sizeof(APT::Solver::State) == 3 * sizeof(int)); @@ -246,23 +246,36 @@ std::string APT::Solver::WhyStr(Reason reason) return outstr; } -bool APT::Solver::Obsolete(pkgCache::VerIterator ver) +bool APT::Solver::Obsolete(pkgCache::PkgIterator pkg) { - if (verObsolete[ver->ID] != 0) - return verObsolete[ver->ID] == 2; + auto ver = policy.GetCandidateVer(pkg); + + if (ver.end() && not StrictPinning) + ver = pkg.VersionList(); + if (ver.end()) + { + std::cerr << "Obsolete: " << pkg.FullName() << " - not installable\n"; + return true; + } + if (pkgObsolete[pkg->ID] != 0) + return pkgObsolete[pkg->ID] == 2; for (auto bin = ver.Cache()->FindGrp(ver.SourcePkgName()).VersionsInSource(); not bin.end(); bin = bin.NextInSource()) - if (bin != ver && bin.ParentPkg()->Arch == ver.ParentPkg()->Arch && bin->ParentPkg != ver->ParentPkg && policy.GetCandidateVer(bin.ParentPkg()) == bin && _system->VS->CmpVersion(bin.SourceVerStr(), ver.SourceVerStr()) > 0) + if (bin != ver && bin.ParentPkg()->Arch == ver.ParentPkg()->Arch && bin->ParentPkg != ver->ParentPkg && (not StrictPinning || policy.GetCandidateVer(bin.ParentPkg()) == bin) && _system->VS->CmpVersion(bin.SourceVerStr(), ver.SourceVerStr()) > 0) { - verObsolete[ver->ID] = 2; + pkgObsolete[pkg->ID] = 2; + if (debug >= 3) + std::cerr << "Obsolete: " << ver.ParentPkg().FullName() << "=" << ver.VerStr() << " due to " << bin.ParentPkg().FullName() << "=" << bin.VerStr() << "\n"; return true; } for (auto file = ver.FileList(); !file.end(); file++) if ((file.File()->Flags & pkgCache::Flag::NotSource) == 0) { - verObsolete[ver->ID] = 1; + pkgObsolete[pkg->ID] = 1; return false; } - verObsolete[ver->ID] = 2; + if (debug >= 3) + std::cerr << "Obsolete: " << ver.ParentPkg().FullName() << "=" << ver.VerStr() << " - not installable\n"; + pkgObsolete[pkg->ID] = 2; return true; } @@ -533,7 +546,7 @@ bool APT::Solver::EnqueueOrGroup(pkgCache::DepIterator start, pkgCache::DepItera { return pkgCache::VerIterator(cache, V).ParentPkg()->CurrentVer == 0; })) workItem.group = Group::SatisfyNew; if (std::any_of(workItem.solutions.begin(), workItem.solutions.end(), [this](auto V) -> auto - { return Obsolete(pkgCache::VerIterator(cache, V)); })) + { return Obsolete(pkgCache::VerIterator(cache, V).ParentPkg()); })) workItem.group = Group::SatisfyObsolete; // Try to perserve satisfied Recommends. FIXME: We should check if the Recommends was there in the installed version? if (workItem.optional && start.ParentPkg()->CurrentVer) diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h index 9a9d67a02..d460c95d9 100644 --- a/apt-pkg/solver3.h +++ b/apt-pkg/solver3.h @@ -104,8 +104,8 @@ class Solver return verStates[V->ID]; } - std::vector verObsolete; - bool Obsolete(pkgCache::VerIterator ver); + std::vector pkgObsolete; + bool Obsolete(pkgCache::PkgIterator pkg); // \brief Heap of the remaining work. // -- cgit v1.2.3-70-g09d2 From ae141932d8b434098e3f77c75c428ca8caff9a6e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 2 Jul 2024 18:53:33 +0200 Subject: solver3: Only demote obsolete packages in choices for upgrades If we are not upgraded, we should continue to keep the installed package installed if possible. --- apt-pkg/solver3.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 29bd3a115..54f66ccd2 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -64,8 +64,9 @@ struct APT::Solver::CompareProviders3 /*{{{*/ // Try obsolete choices only after exhausting non-obsolete choices such that we install // packages replacing them and don't keep back upgrades depending on the replacement to // keep the obsolete package installed. - if (auto obsoleteA = Solver.Obsolete(A), obsoleteB = Solver.Obsolete(B); obsoleteA != obsoleteB) - return obsoleteB; + if (upgrade) + if (auto obsoleteA = Solver.Obsolete(A), obsoleteB = Solver.Obsolete(B); obsoleteA != obsoleteB) + return obsoleteB; // Prefer MA:same packages if other architectures for it are installed if ((AV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same || (BV->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same) -- cgit v1.2.3-70-g09d2 From a16350427b8ce3865d2f11e637952210d34ee410 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 2 Jul 2024 18:56:40 +0200 Subject: solver3: Formatting cleanup Run clang-format --- apt-pkg/solver3.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc index 54f66ccd2..67aa68dca 100644 --- a/apt-pkg/solver3.cc +++ b/apt-pkg/solver3.cc @@ -155,8 +155,8 @@ class DefaultRootSetFunc2 : public pkgDepCache::DefaultRootSetFunc std::unique_ptr Kernels; public: - DefaultRootSetFunc2(pkgCache *cache) : Kernels(APT::KernelAutoRemoveHelper::GetProtectedKernelsFilter(cache)){}; - virtual ~DefaultRootSetFunc2(){}; + DefaultRootSetFunc2(pkgCache *cache) : Kernels(APT::KernelAutoRemoveHelper::GetProtectedKernelsFilter(cache)) {}; + virtual ~DefaultRootSetFunc2() {}; bool InRootSet(const pkgCache::PkgIterator &pkg) APT_OVERRIDE { return pkg.end() == false && ((*Kernels)(pkg) || DefaultRootSetFunc::InRootSet(pkg)); }; }; // FIXME: DEDUP with pkgDepCache. @@ -306,7 +306,7 @@ bool APT::Solver::Install(pkgCache::PkgIterator Pkg, Reason reason, Group group) // Note decision if (unlikely(debug >= 1)) std::cerr << "[" << depth() << "] Install:" << Pkg.FullName() << " (" << WhyStr(reason) << ")\n"; - (*this)[Pkg] = {reason, depth(), Decision::MUST,}; + (*this)[Pkg] = {reason, depth(), Decision::MUST}; // Insert the work item. Work workItem{Reason(Pkg), depth(), group}; @@ -356,9 +356,9 @@ bool APT::Solver::Install(pkgCache::VerIterator Ver, Reason reason, Group group) // Note decision if (unlikely(debug >= 1)) std::cerr << "[" << depth() << "] Install:" << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " (" << WhyStr(reason) << ")\n"; - (*this)[Ver] = {reason, depth(), Decision::MUST,}; + (*this)[Ver] = {reason, depth(), Decision::MUST}; if ((*this)[Ver.ParentPkg()].decision != Decision::MUST) - (*this)[Ver.ParentPkg()] = {Reason(Ver), depth(), Decision::MUST,}; + (*this)[Ver.ParentPkg()] = {Reason(Ver), depth(), Decision::MUST}; for (auto OV = Ver.ParentPkg().VersionList(); not OV.end(); ++OV) { @@ -395,7 +395,7 @@ bool APT::Solver::Reject(pkgCache::PkgIterator Pkg, Reason reason, Group group) // Reject the package and its versions. if (unlikely(debug >= 1)) std::cerr << "[" << depth() << "] Reject:" << Pkg.FullName() << " (" << WhyStr(reason) << ")\n"; - (*this)[Pkg] = {reason, depth(), Decision::MUSTNOT,}; + (*this)[Pkg] = {reason, depth(), Decision::MUSTNOT}; for (auto ver = Pkg.VersionList(); not ver.end(); ver++) if (not Reject(ver, Reason(Pkg), group)) return false; @@ -408,7 +408,7 @@ bool APT::Solver::Reject(pkgCache::PkgIterator Pkg, Reason reason, Group group) // \brief Do not install this version bool APT::Solver::Reject(pkgCache::VerIterator Ver, Reason reason, Group group) { - (void) group; + (void)group; if ((*this)[Ver].decision == Decision::MUSTNOT) return true; @@ -423,7 +423,7 @@ bool APT::Solver::Reject(pkgCache::VerIterator Ver, Reason reason, Group group) // Mark the package as rejected and propagate up as needed. if (unlikely(debug >= 1)) std::cerr << "[" << depth() << "] Reject:" << Ver.ParentPkg().FullName() << "=" << Ver.VerStr() << " (" << WhyStr(reason) << ")\n"; - (*this)[Ver] = {reason, depth(), Decision::MUSTNOT,}; + (*this)[Ver] = {reason, depth(), Decision::MUSTNOT}; if (auto pkg = Ver.ParentPkg(); (*this)[pkg].decision != Decision::MUSTNOT) { bool anyInstallable = false; -- cgit v1.2.3-70-g09d2