rmdepcheck always fails with bogus errors from krb5-server, insights-client, gnome-keyring on EPEL 9 #23
Labels
No labels
ai-review-please
Backlog Status
Needs Review
Backlog Status
Ready
chore
documentation
points
01
points
02
points
03
points
05
points
08
points
13
pr2jira
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Sprint Status
Blocked
Sprint Status
Done
Sprint Status
In Progress
Sprint Status
Review
Sprint Status
To Do
Technical Debt
Work Item
Bug
Work Item
Epic
Work Item
Spike
Work Item
Task
Work Item
User Story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
quality/rmdepcheck#23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
I'm baffled as to why ATM, but it seems like whenever it's run on EPEL 9, rmdepcheck gives a bunch of bogus failures:
Trying to figure this out. It's very weird.
Aha, figured it out. When setting up the modified base repos, we only download the
primaryrepodata, because I thought this contained everything we need. But it doesn't. It only includes files in/etcand/usr/bin; info on the files in each package outside those paths is in thefilelistsmetadata.The problematic deps are file-based deps outside of the paths that are in the
primaryrepodata. So when we do the unmodified repoclosure, using the real repodata, those deps are OK. When we do the modified repoclosure, using the modified repodata which contains onlyprimary, those deps show up as not OK because we don't know the 'words' package contains/usr/share/dict/wordsetc.To fix this, we need to download
filelistsas well asprimary. And modify it too, I guess, to remove the same packages we remove from the primary repodata.OK, well, this is proving more complex than expected. I added download and parsing of the filelist data and...the script promptly ground to a halt and hung my system till it got OOM killed. At first I thought I did something wrong, then I realized nope, that's not it, these are just sodding huge files, and we're parsing them with
et.parse(), which loads the entire thing into memory. Loading EPEL 9 primary metadata actually uses 8G already (I'm a bit surprised the script doesn't choke when running in openQA, tbh) and loading the filelist metadata on top of that just blows away all my RAM.I think I need to switch the metadata replacement function to using
iterparse()instead, but I've got to go out in 20 minutes, so I'll do it tomorrow.ugh, so, today's progress: even
iterparsedoesn't work easily, because the list of packages is nested inside one big<metadatathat we also need to output, but to do that we need to load the whole thing into memory, I think...well, maybe there's a way to make it work, but I skipped instead to "write a hacky line parser that does just enough XML parsing to get the info we need".This works, and uses less memory, but it's still very slow; parsing the filelists metadata for EPEL 9 takes ~8 minutes. This may just be as fast as we can read 1.8GB of text from disk and flush it back out again, I dunno, but I'll try optimizing it. (One idea is to figure out when we've deleted the last binary package from the filelists metadata and then quit parsing line-by-line and just flush the entire rest of the file into the 'modified' output; I don't know yet if this actually makes it any faster, though).
Another option is to not modify the filelists metadata, just copy it through unmodified, and trust that dnf just ignores filelists entries for packages that don't exist in primary (and doesn't use them to resolve dependencies). I may test this, and if it turns out to be the case, just go with that - just copy filelists into the 'modified' repodata without modification. It's faster at least.
Finally, another wrinkle showed up at the end: we also need to include the modularity metadata (modules.yaml.zst) in the modified repodata, or else all module packages are available to dnf's solver when doing repoclosure on the modified repo and we get some false "fixed" dependencies for non-modular packages:
those show up as "fixed" because there are appropriately-versioned nodejs and postgresql packages available in modules, but it's not valid for a non-module package to require a module package; if the repodata doesn't include the module metadata, though, all module packages are treated as non-module packages. So I need to copy the module metadata over too.
OK, I now have a working fix, and thanks to Claude it's pretty fast (my version: 10 minutes, Claude's: 10 seconds), but I'm not sure I love it. I want to try an alternative approach and see if that works. Will probably pick one or the other tomorrow or Monday.
#24 is the Cursor/Claude text parser fix; #25 is my hack-around-iterparse fix. I've cleaned them both up to pass CI and tests. I'll probably go ahead and merge my iterparse version soon, but I might look into a third option - using pygixml or pugixml-python - first. I also might hack up openQA to run all the options and compare the results, that might be fun.
So I came up with a different third option which is looking quite nice. It's a hybrid of #24 and #25: we read the file in as a chunked bytestream and parse out the package chunks, as in #24; we then parse the individual chunks with a real XML parser as in #25, not regexes as in #24. But we don't write back out with
tostringlike we do in #25 - we just use the XML parser to read the package blob and decide whether it should be skipped; if not, we write through the original unmodified bytes. All bytes outside of a package blob are written through unmodified.With ElementTree this isn't any faster than #25, but with lxml it's nearly as fast as #24, while being (I reckon) substantially less fragile, but also has #24 's benefit of passing through the original input text unmodified except for the removals (in #25, ElementTree .tostring reformats the output somewhat). I couldn't use lxml in #25 because for some reason when I try to swap in lxml's iterparse for ElementTree's, it chokes and I couldn't figure out why or fix it.
I'll clean this up some tomorrow and post it as a new PR, then probably merge that one, I think.
I've merged #26 , so this should be fixed now. Let's hope.
Although, hmm. The end boss fourth approach to optimizing XML parsing might be...don't do XML parsing any more...