Hi!

I was curious if all these ideas really translate into a performance improvement. Attached patch reenables delta resolving and resolves FileRequires globally.

Delta Resolving:
I moved the delta list into the TransactionData object to get really all changes (got caught by the installonlyn plugin). Now packages are only removed from the delta if there are no unresolved dependencies. This reliefs the depsolver from having to perfectly solve everything (see rev 1.138 of depsolver.py)

I am still a bit unsure about TransactionData.remove(). To make delta resolving work removed installs have to be treated as removes. Can this currently happen at all?

Global File Require Resolving:
Most stuff about it is already said. Current implementation always checks file requirements. This could be avoided if there are no erases/updates since the last successful (everything ok) run.

On my PC "echo n |yum update" is now appr. 100% faster when trying
to update 60 pkgs. Larger and more complicated cases or packages with lots of files may gain even more.

When I create PkgPrco indices in the sqlite I get another 7% speed up which is not much but not surprising as we only load a few pkg from the sqlite db.

have fun

        Florian

PS: I have the feeling that the yum sqlite db interface is slow. It might be a problem of either generating a cursor on every search or/and pkgId=pkgKey merge. But didn't do any measurements yet.
Index: yum/depsolve.py
===================================================================
RCS file: /cvsroot/yum/cvs/yum/yum/depsolve.py,v
retrieving revision 1.142
diff -u -r1.142 depsolve.py
--- yum/depsolve.py	19 Mar 2007 20:29:03 -0000	1.142
+++ yum/depsolve.py	20 Mar 2007 14:35:41 -0000
@@ -43,7 +43,6 @@
         self.dsCallback = None
         self.logger = logging.getLogger("yum.Depsolve")
         self.verbose_logger = logging.getLogger("yum.verbose.Depsolve")
-        self.tsInfoDelta = []
     
     def doTsSetup(self):
         warnings.warn('doTsSetup() will go away in a future version of Yum.\n',
@@ -510,7 +509,6 @@
                 requiringPo, needname)
             txmbr = self.tsInfo.addErase(requiringPo)
             txmbr.setAsDep(po=needpo)
-            self.tsInfoDelta.append(txmbr)
             checkdeps = 1
         
         if needmode in ['i', 'u']:
@@ -532,7 +530,6 @@
                             txmbr = self.tsInfo.addObsoleting(po, requiringPo)
                             self.tsInfo.addObsoleted(requiringPo, po)
                             txmbr.setAsDep(po=needpo)
-                            self.tsInfoDelta.append(txmbr)
                             self.verbose_logger.log(logginglevels.DEBUG_2, 'TSINFO: Obsoleting %s with %s to resolve dep.', 
                                 requiringPo, po)
                             checkdeps = 1
@@ -564,7 +561,6 @@
                     if po.pkgtup == new:
                         txmbr = self.tsInfo.addUpdate(po, requiringPo)
                         txmbr.setAsDep(po=needpo)
-                        self.tsInfoDelta.append(txmbr)
                         self.verbose_logger.log(logginglevels.DEBUG_2, 'TSINFO: Updating %s to resolve dep.', po)
                 checkdeps = 1
                 
@@ -706,13 +702,11 @@
             # FIXME: we should probably handle updating multiple packages...
             txmbr = self.tsInfo.addUpdate(best, inst[0])
             txmbr.setAsDep()
-            self.tsInfoDelta.append(txmbr)
         else:
             self.verbose_logger.debug('TSINFO: Marking %s as install for %s', best,
                 name)
             txmbr = self.tsInfo.addInstall(best)
             txmbr.setAsDep()
-            self.tsInfoDelta.append(txmbr)
 
         checkdeps = 1
         
@@ -773,7 +767,6 @@
                 'TSINFO: Updating %s to resolve conflict.', po)
             txmbr = self.tsInfo.addUpdate(po, confpkg)
             txmbr.setAsDep()
-            self.tsInfoDelta.append(txmbr)
             CheckDeps = 1
             
         else:
@@ -806,6 +799,8 @@
         self.deps = {}
         self.path = []
         self.loops = []
+        self.installedFileRequires = None
+        self.installedUnresolvedFileRequires = None
 
     def _provideToPkg(self, req):
         best = None
@@ -833,7 +828,7 @@
             if self.tsInfo.getMembers(po.pkgtup):
                 self.deps[req] = po
                 return po
-        
+
         for txmbr in self.tsInfo.getMembers(None, TS_INSTALL_STATES):
             if txmbr.po.checkPrco('provides', (r, f, v)):
                 self.deps[req] = txmbr.po
@@ -841,12 +836,6 @@
                 
         return None # for new ts check attempt
 
-    def _undoDepInstalls(self):
-        # clean up after ourselves in the case of failures
-        for txmbr in self.tsInfo:
-            if txmbr.isDep:
-                self.tsInfo.remove(txmbr.pkgtup)
-
     def prof_resolveDeps(self):
         fn = "anaconda.prof.0"
         import hotshot, hotshot.stats
@@ -857,7 +846,9 @@
         stats = hotshot.stats.load(fn)
         stats.strip_dirs()
         stats.sort_stats('time', 'calls')
-        stats.print_stats(20)
+        stats.print_stats(40)
+        stats.sort_stats("cumulative")
+        stats.print_stats(40)
         return rc
 
     def cprof_resolveDeps(self):
@@ -877,7 +868,8 @@
         # returns a list of tuples
         # ((name, version, release), (needname, needversion), flags, suggest, sense)
         ret = []
-        for txmbr in self.tsInfo.getMembers():
+        for txmbr in self.tsInfo.delta.copy():
+            l = len(ret)
             self.verbose_logger.log(logginglevels.INFO_2,
                                     "Checking deps for %s" %(txmbr,))
             if txmbr.output_state in (TS_INSTALL, TS_TRUEINSTALL, TS_OBSOLETING):
@@ -887,7 +879,14 @@
             elif txmbr.output_state in TS_REMOVE_STATES:
                 ret.extend(self._checkRemove(txmbr))
 
-        self.tsInfoDelta = []
+            if len(ret) == l:
+                # no unresolved
+                self.tsInfo.delta.remove(txmbr)
+
+        self.verbose_logger.log(logginglevels.INFO_2,
+                                "Checking file requirements")
+        ret.extend(self._checkFileRequires())
+                
         return ret
 
     def _resolveDeps(self):
@@ -900,7 +899,6 @@
         errors = []
         if self.dsCallback: self.dsCallback.start()
 
-        self.tsInfoDelta = self.tsInfo.getMembers()
         while CheckDeps:
             self.cheaterlookup = {} # short cache for some information we'd resolve
                                     # (needname, needversion) = pkgtup
@@ -1015,9 +1013,9 @@
 
         # if this is an update, we should check what the old
         # requires were to make things faster
-        oldreqs = []
+        oldreqs = set()
         for oldpo in txmbr.updates:
-            oldreqs.extend(oldpo.returnPrco('requires'))
+            oldreqs.update(oldpo.returnPrco('requires'))
 
         ret = []
         for req in reqs:
@@ -1073,11 +1071,6 @@
         po = txmbr.po
         provs = po.returnPrco('provides')
 
-        # get the files in the package and express them as "provides"
-        files = po.filelist
-        filesasprovs = map(lambda f: (f, None, (None,None,None)), files)
-        provs.extend(filesasprovs)
-
         # if this is an update, we should check what the new package
         # provides to make things faster
         newpoprovs = []
@@ -1090,8 +1083,6 @@
         for prov in provs:
             if prov[0].startswith('rpmlib('): # ignore rpmlib() provides
                 continue
-            if prov[0].startswith("/usr/share/doc"): # XXX: ignore doc files
-                continue
             if prov in newpoprovs:
                 continue
 
@@ -1207,3 +1198,53 @@
                              flags[f], None, rpm.RPMDEP_SENSE_REQUIRES) )
 
         return ret
+
+    def _checkFileRequires(self):
+        # XXX move to TransactionData
+        newPkgs = self._tsInfo.getMembers(output_states=TS_INSTALL_STATES)
+        removedPkgs = set((txmbr.po for txmbr in self._tsInfo.getMembers(
+            output_states=TS_REMOVE_STATES)))
+
+        fileRequires = set()
+        reverselookup = {}
+        ret = []
+
+        # get file requirements from new packages
+        for txmbr in newPkgs:
+            for name, flag, evr in txmbr.po.requires:
+                if name.startswith('/'):
+                    fileRequires.add(name)
+                    reverselookup.setdefault(name, []).append(txmbr.po)
+
+        # generate list of file requirement in rpmdb
+        if self.installedFileRequires is None:
+            self.installedFileRequires = {}
+            self.installedUnresolvedFileRequires = set()
+            resolved = set()
+            for pkg in self.rpmdb.returnPackages():
+                for name, flag, evr in pkg.requires:
+                    if not name.startswith('/'):
+                        continue
+                    self.installedFileRequires.setdefault(pkg, []).append(name)
+                    if name not in resolved:
+                        dep = self.rpmdb.whatProvides(name, flag, evr)
+                        resolved.add(name)
+                        if not dep:
+                            self.installedUnresolvedFileRequires.add(name)
+
+        for po, files in self.installedFileRequires.iteritems():
+            if po not in removedPkgs:
+                fileRequires.update(files)
+                for filename in files:
+                    reverselookup.setdefault(filename, []).append(po)
+
+        fileRequires -= self.installedUnresolvedFileRequires
+
+        for filename in fileRequires:
+            dep = self._provideToPkg((filename, None, (None, None, None)))
+            if not dep:
+                for po in reverselookup[filename]:
+                    ret.append( ((po.name, po.version, po.release),
+                                 (filename, ''), 0, None,
+                                 rpm.RPMDEP_SENSE_REQUIRES) )
+        return ret
Index: yum/transactioninfo.py
===================================================================
RCS file: /cvsroot/yum/cvs/yum/yum/transactioninfo.py,v
retrieving revision 1.37
diff -u -r1.37 transactioninfo.py
--- yum/transactioninfo.py	22 Feb 2007 03:47:23 -0000	1.37
+++ yum/transactioninfo.py	20 Mar 2007 14:35:41 -0000
@@ -32,6 +32,7 @@
         self.probFilterFlags = []
         self.root = '/'
         self.pkgdict = {} # key = pkgtup, val = list of TransactionMember obj
+        self.delta = set()
         self.debug = 0
         self.changed = False
         
@@ -146,7 +147,7 @@
                     return
         self.pkgdict[txmember.pkgtup].append(txmember)
         self.changed = True
-
+        self.delta.add(txmember)
         if self.conditionals.has_key(txmember.name):
             for po in self.conditionals[txmember.name]:
                 condtxmbr = self.addInstall(po)
@@ -160,6 +161,13 @@
             return
         for txmbr in self.pkgdict[pkgtup]:
             txmbr.po.state = None
+            self.delta.discard(txmbr)
+            if txmbr.output_state in TS_INSTALL_STATES:
+                # insert dummy into delta to check if this breaks deps
+                # XXX really needed?
+                check_txmbr = TransactionMember(txmbr.po)
+                check_txmbr.output_state = TS_ERASE
+                self.delta.add(check_txmbr)
         
         del self.pkgdict[pkgtup]
         self.changed = True        
_______________________________________________
Yum-devel mailing list
[email protected]
https://lists.dulug.duke.edu/mailman/listinfo/yum-devel

Reply via email to