Sometime recently yum-security in "list updates mode"[1] has started
causing backtraces and taking a huge amount of time.

 For those that don't know the way plugins exclude items frfom "list
updates" is to use the exclude_hook and call conduit.getPackages and the
conduit.delPackage for any that they don't want.

 The speed problem seems to be that conduit.delPackage() now takes about
a quarter of a second or so, combined with having to remove most/all of
the pacakges on the system.


 The traceback is due to the fact that yum-security just did:

  for pkg in conduit.getPackages():

...and this recurses into the function that calls the exclude plugins,
YumBase._getSacks(), and is protected from that being a problem by
doing:

        if self._pkgSack and thisrepo is None:

...but if you remove _all_ of the packages the above fails. This can be
fixed by just moving the getPackages to a variable before the for loop
like:

pkgs = conduit.getPackages()
for pkg in pkgs:

...however I fixed that and the speed problem by instead doing:

upds = conduit._base.doPackageLists(pkgnarrow='updates')
pkgs = upds.updates

...this feels a little hacky, but it takes the runtime on my machine
from about an hour to 5 seconds (so I feel a little justified :).
 Another way to go is if we could test if the package is an
update/installed etc, like:

pkgs = conduit.getPackages()
for pkg in pkgs:
   if <pkg isn't installed already>:
       # Do our normal work, incl. likely delPackage()

...but I don't think that's available at this point.

 Full patch against yum-utils is attached.

[1] Ie. yum list updates --security

-- 
James Antill <[EMAIL PROTECTED]>
Red Hat
diff --git a/plugins/security/security.py b/plugins/security/security.py
index 9d97a3b..f8f1cf8 100755
--- a/plugins/security/security.py
+++ b/plugins/security/security.py
@@ -338,10 +338,27 @@ def exclude_hook(conduit):
         conduit.delPackage(pkg)
 
     used_map = ysp_gen_used_map(opts)
-    for pkg in conduit.getPackages():
-        if not ysp_should_keep_pkg(opts, pkg, md_info, used_map):
+    # The official API is:
+    #
+    # pkgs = conduit.getPackages()
+    #
+    # ...however that is _extremely_ slow, deleting all packages. So we ask
+    # for the list of update packages, which is all we care about.
+    upds = conduit._base.doPackageLists(pkgnarrow='updates')
+    pkgs = upds.updates
+    tot = 0
+    cnt = 0
+    for pkg in pkgs:
+        tot += 1
+        if ysp_should_keep_pkg(opts, pkg, md_info, used_map):
+            cnt += 1
+        else:
             ysp_del_pkg(pkg)
     ysp_chk_used_map(used_map, lambda x: conduit.error(2, x))
+    if cnt:
+        conduit.info(2, 'Needed %d of %d packages, for security' % (cnt, tot))
+    else:
+        conduit.info(2, 'No packages needed, for security, %d available' % tot)
             
 def preresolve_hook(conduit):
     '''
@@ -366,11 +383,13 @@ def preresolve_hook(conduit):
                      (tspkg.po,tspkg.po.repoid))
         tsinfo.remove(tspkg.pkgtup)
 
+    tot = 0
     cnt = 0
     used_map = ysp_gen_used_map(opts)
     tsinfo = conduit.getTsInfo()
     tspkgs = tsinfo.getMembers()
     for tspkg in tspkgs:
+        tot += 1
         if not ysp_should_keep_pkg(opts, tspkg.po, md_info, used_map):
             ysp_del_pkg(tspkg)
         else:
@@ -378,9 +397,9 @@ def preresolve_hook(conduit):
     ysp_chk_used_map(used_map, lambda x: conduit.error(2, x))
     
     if cnt:
-        conduit.info(2, 'Needed %d packages, for security' % (cnt))
+        conduit.info(2, 'Needed %d of %d packages, for security' % (cnt, tot))
     else:
-        conduit.info(2, 'No packages needed, for security')
+        conduit.info(2, 'No packages needed, for security, %d available' % tot)
 
 if __name__ == '__main__':
     print "This is a plugin that is supposed to run from inside YUM"

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
Yum-devel mailing list
[email protected]
https://lists.dulug.duke.edu/mailman/listinfo/yum-devel

Reply via email to