[Yum-devel] [PATCH] Update metadata only when installed packages are to be updated.

Zdenek Pavlas zpavlas at redhat.com
Tue Apr 30 16:38:14 UTC 2013


Not to be merged, just a POC that could later evolve to some form
of incremental metadata updates.  When option lazymdupdates is on,
we don't download new metadata unless it provides updated version
of some installed package.

This relies on director listing, and is thus not reliable neither
server-friendly.  Should be replaced with a custom repomd.xml data.

TBD:  Instead of update check, we can download new RPM headers
and sync the primary & filelists db incrementally.  The updated
databases will very likely NOT be byte-compatible, but since now
Yum uses xattrs for caching checksum, we can abuse it.
---
 yum/__init__.py |  1 +
 yum/config.py   |  2 ++
 yum/yumRepo.py  | 43 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/yum/__init__.py b/yum/__init__.py
index 50e2fad..5c15b37 100644
--- a/yum/__init__.py
+++ b/yum/__init__.py
@@ -223,6 +223,7 @@ class YumBase(depsolve.Depsolve):
         self.exit_code = 0
 
         self.updateinfo_filters = {}
+        yumRepo._ayum = self # hack
 
     def __del__(self):
         self.close()
diff --git a/yum/config.py b/yum/config.py
index ec7ba80..0079161 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -811,6 +811,7 @@ class YumConf(StartupConf):
     # similar but better :).
     mdpolicy = ListOption(['group:primary'])
     mddownloadpolicy = SelectionOption('sqlite', ('sqlite', 'xml'))
+    lazymdupdates = SecondsOption(0)
     #  ('instant', 'group:all', 'group:main', 'group:small', 'group:primary'))
     multilib_policy = SelectionOption(__main_multilib_policy_default__,
                                       ('best', 'all'))
@@ -962,6 +963,7 @@ class RepoConf(BaseConfig):
     #       checksumming of the repomd.xml.
     mdpolicy = Inherit(YumConf.mdpolicy)
     mddownloadpolicy = Inherit(YumConf.mddownloadpolicy)
+    lazymdupdates = Inherit(YumConf.lazymdupdates)
     cost = IntOption(1000)
     
     sslcacert = Inherit(YumConf.sslcacert)
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
index 2e4fcd9..4e882a0 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
@@ -51,6 +51,7 @@ import shutil
 import stat
 import errno
 import tempfile
+from rpm import labelCompare
 
 # This is unused now, probably nothing uses it but it was global/public.
 skip_old_DBMD_check = False
@@ -1355,7 +1356,47 @@ Insufficient space in download directory %s
                            (time.ctime(old_repo_XML.timestamp),
                             time.ctime(self.repoXML.timestamp)))
             return False
-        return True
+
+        # check if delayed updating is on
+        if not self.lazymdupdates:
+            return True
+        if self.repoXML.timestamp - old_repo_XML.timestamp > self.lazymdupdates:
+            return True
+
+        # attempt to retrieve the package index
+        index = self.cachedir + '/index'
+        try: t = int(os.path.getmtime(index))
+        except OSError: t = None
+        if t != self.repoXML.timestamp:
+            pkgs = []
+            tmp = index + '.tmp'
+            new = self._getFile(relative='', local=tmp, text='%s/index' % self)
+            for l in open(new):
+                m = re.search(' href="(.*/)?(.+?)\\.rpm"', l)
+                if m: pkgs.append(m.group(2) + '\n')
+            open(tmp, 'w').write(''.join(pkgs))
+            os.utime(tmp, (0, self.repoXML.timestamp))
+            os.rename(tmp, index)
+        else:
+            pkgs = list(open(index))
+        if not pkgs:
+            return True
+
+        # check if there are some updates
+        count = 0
+        search = _ayum.rpmdb._search
+        for pkg in pkgs:
+            n, v, r, a = re.search('(.+)-(.+)-(.+)\\.(.+)', pkg).groups()
+            best = None
+            for po in search(name=n, arch=a):
+                evr = None, po.version, po.release
+                if not best or labelCompare(evr, best) > 0:
+                    best = evr
+            evr = None, v, r
+            if best and labelCompare(evr, best) > 0:
+                count += 1
+        verbose_logger.info('%s: %d updates', self.ui_id, count)
+        return count > 0
 
     @staticmethod
     def _checkRepoXMLMetalink(repoXML, repomd):
-- 
1.7.11.7



More information about the Yum-devel mailing list