-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
goal: Better handling of obsoleted pkg installation #354
Conversation
Oh, the test for this issue is already present so I'll only change it according to the changed behavior. |
libdnf/base/goal.cpp
Outdated
libdnf::rpm::PackageQuery data_query(base_query.get_base(), libdnf::sack::ExcludeFlags::APPLY_EXCLUDES, true); | ||
data_query.update(data); | ||
data_query.filter_priority(); | ||
data_query.filter_latest_evr(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am thinking about two edge cases where we might have a problem. Both cases are related to situation when package name is installed.
- When vendor change is not allowed (configuration allow_vendor_change)
- We will have a different set of candidates in comparison to upgrade request with the same argument
I have a suggestion - if data
contains installed package than use the original approach. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have test scenarios for these situations. I'll try to prepare them - it will definitely help me wrap my head around it.
e3b2fe1
to
d50c2bc
Compare
libdnf/base/goal.cpp
Outdated
@@ -45,8 +45,26 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>. | |||
namespace { | |||
|
|||
void add_obsoletes_to_data(const libdnf::rpm::PackageQuery & base_query, libdnf::rpm::PackageSet & data) { | |||
libdnf::rpm::PackageQuery data_query(base_query.get_base(), libdnf::sack::ExcludeFlags::APPLY_EXCLUDES, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a problem of the PR - The creation of an empty query was cryptic to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about to have query constructor with packageset and flags?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup. The reason is to by-pass the missing constructor.
It looks like that one test is failing
I looked at the bug and it looks like that test is wrong (keeping wrong behavior) and your patch fix it. May I ask you to modify the test? |
It's a shortcut instead of creating an empty PackageQuery and then updating it with the content of PackageSet.
In situation where a package exists in multiple versions and some older version is being obsoleted, any of obsoleters was considered a valid solution. The result could be really misleading. For example let's have this package set: systemd-udev-1.0 systemd-udev-2.0 Obsoletes: systemd-udev < 2 systemd-boot-unsigned-2.0 Obsoletes: systemd-udev < 2 In this case `dnf install systemd-udev` may lead to installation of systemd-boot-unsigned which is probably not what the user expected. The reason is the split in the upgrade-path created by obsolete and both branches - systemd-udev-2.0 and systemd-boot-unsigned-2.0 are considered valid. With this patch install command takes into account only obsoleters of the best version of the package so the `dnf install systemd-udev` results in correct installation of systemd-udev-2.0 package.
d50c2bc
to
28ad621
Compare
@@ -267,6 +267,11 @@ PackageQuery::PackageQuery(const BaseWeakPtr & base, ExcludeFlags flags, bool em | |||
PackageQuery::PackageQuery(libdnf::Base & base, ExcludeFlags flags, bool empty) | |||
: PackageQuery(base.get_weak_ptr(), flags, empty) {} | |||
|
|||
PackageQuery::PackageQuery(const PackageSet & pkgset, ExcludeFlags flags) | |||
: PackageQuery(pkgset.get_base(), flags, true) { | |||
update(pkgset); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is functional but it looks like a strange implementation. I have to check internals
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor could look like following. But there is one small difference - creation of empty Map nad and operator vs copy of Map. And it is more code.
PackageQuery::PackageQuery(const PackageSet & pkgset, ExcludeFlags flags)
: PackageSet(src), p_pq_impl(new PQImpl) {
p_pq_impl->flags = flags;
auto & pool = get_rpm_pool(base);
switch (flags) {
case ExcludeFlags::APPLY_EXCLUDES:
// Considered map in Pool uses APPLY_EXCLUDES. It can be used in this case.
base->get_rpm_package_sack()->p_impl->recompute_considered_in_pool();
break;
case ExcludeFlags::IGNORE_EXCLUDES:
break;
default: {
auto considered = base->get_rpm_package_sack()->p_impl->compute_considered_map(flags);
if (considered) {
p_pq_impl->considered_cache = std::move(considered);
}
break;
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please the decision is up to you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand your solution introduces code duplicity (it's basically a copy of current PackageQuery ctor).
I don't know, the difference in performance is one SolvMap |
operation. Maybe if this constructor is massively used, then even this small performance increase may make a difference. But now there is only one place where this constructor is actually used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or would it be better from your point of view to use directly something like *p_impl |= *pkgset.p_impl
instead of update()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no performance difference between both solutions. Creation of Map and copy is cheap. And I agree that there is an overlap with other code.
LGTM |
In situation where a package exists in multiple versions and some older version is being obsoleted, any of obsoleters was considered a valid solution.
The result could be really misleading. For example let's have this package set:
systemd-udev-1.0
systemd-udev-2.0
Obsoletes: systemd-udev < 2
systemd-boot-unsigned-2.0
Obsoletes: systemd-udev < 2
In this case
dnf install systemd-udev
may lead to installation of systemd-boot-unsigned which is probably not what the user expected. The reason is the split in the upgrade-path created by obsolete and both branches - systemd-udev-2.0 and systemd-boot-unsigned-2.0 are considered valid.With this patch install command takes into account only obsoleters of the best version of the package so the
dnf install systemd-udev
results in correct installation of systemd-udev-2.0 package.Resolves: #339
Requires tests adjustment: rpm-software-management/ci-dnf-stack#1236