[Yum-devel] [PATCH 1/8] Add a metadata_expire_filter configuration, and use it in the shipped commands.

James Antill james at and.org
Wed Jan 16 07:25:59 UTC 2013


 In theory this is never needed because everyone always runs yum-cron
and repos. are always upto date. In practise everyone complains because
yum hits the network due to that not being the case. This allows the
user to control a lot better how much out of data info. they don't mind
having for simple "yum search" type commands etc.

 Not sure how useful the past/present distinction is, but it's easier to
ignore/remove it that to add it back in later.
---
 cli.py          |    6 +++
 docs/yum.conf.5 |   30 +++++++++++++
 yum/config.py   |    5 ++
 yum/yumRepo.py  |   23 +++++++++-
 yumcommands.py  |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 192 insertions(+), 2 deletions(-)

diff --git a/cli.py b/cli.py
index 9225d5a..01b21e6 100755
--- a/cli.py
+++ b/cli.py
@@ -509,6 +509,12 @@ class YumBaseCli(yum.YumBase, output.YumOutput):
             except yum.Errors.YumBaseError, e:
                 return 1, [exception2msg(e)]
 
+        cacheReq = 'write'
+        if hasattr(cmd, 'cacheRequirement'):
+            cacheReq = cmd.cacheRequirement(self, self.basecmd, self.extcmds)
+        for repo in self.repos.listEnabled():
+            repo._metadata_cache_req = cacheReq
+
         return self.yum_cli_commands[self.basecmd].doCommand(self, self.basecmd, self.extcmds)
 
     def doTransaction(self):
diff --git a/docs/yum.conf.5 b/docs/yum.conf.5
index 029fa75..30ac844 100644
--- a/docs/yum.conf.5
+++ b/docs/yum.conf.5
@@ -499,6 +499,31 @@ It's also possible to use the word "never", meaning that the metadata will
 never expire. Note that when using a metalink file the metalink must always
 be newer than the metadata for the repository, due to the validation, so this
 timeout also applies to the metalink file.
+Also note that "never" does not override "yum clean expire-cache"
+
+.IP
+\fBmetadata_expire_filter \fR
+Filter the metadata_expire time, allowing a trade of speed for accuracy if
+a command doesn't require it. Each yum command can specify that it requires a
+certain level of timeliness quality from the remote repos. from "I'm about to
+install/upgrade, so this better be current" to "Anything that's available
+is good enough".
+
+'never' - Nothing is filtered, always obey metadata_expire.
+
+'read-only:past' - Commands that only care about past information
+are filtered from metadata expiring.
+Eg. yum history info (if history needs to lookup anything about a previous
+transaction, then by definition the remote package was available in the past).
+
+'read-only:present' - Commands that are balanced between past and future.
+This is the default.
+Eg. yum list yum
+
+'read-only:future' - Commands that are likely to result in running other
+commands which will require the latest metadata. Eg. yum check-update
+
+Note that this option does not override "yum clean expire-cache".
 
 .IP
 \fBmirrorlist_expire \fR
@@ -911,6 +936,11 @@ Overrides the \fBmetadata_expire\fR option from the [main] section for this
 repository.
 
 .IP
+\fBmetadata_expire_filter \fR
+Overrides the \fBmetadata_expire_filter\fR option from the [main] section for
+this repository.
+
+.IP
 \fBmirrorlist_expire \fR
 Overrides the \fBmirrorlist_expire\fR option from the [main] section for this
 repository.
diff --git a/yum/config.py b/yum/config.py
index 74be397..3cdb0fd 100644
--- a/yum/config.py
+++ b/yum/config.py
@@ -792,6 +792,10 @@ class YumConf(StartupConf):
 
     http_caching = SelectionOption('all', ('none', 'packages', 'all'))
     metadata_expire = SecondsOption(60 * 60 * 6) # Time in seconds (6h).
+    metadata_expire_filter = SelectionOption('read-only:present',
+                                             ('never', 'read-only:future',
+                                              'read-only:present',
+                                              'read-only:past'))
     # Time in seconds (1 day). NOTE: This isn't used when using metalinks
     mirrorlist_expire = SecondsOption(60 * 60 * 24)
     # XXX rpm_check_debug is unused, left around for API compatibility for now
@@ -944,6 +948,7 @@ class RepoConf(BaseConfig):
 
     http_caching = Inherit(YumConf.http_caching)
     metadata_expire = Inherit(YumConf.metadata_expire)
+    metadata_expire_filter = Inherit(YumConf.metadata_expire_filter)
     mirrorlist_expire = Inherit(YumConf.mirrorlist_expire)
     # NOTE: metalink expire _must_ be the same as metadata_expire, due to the
     #       checksumming of the repomd.xml.
diff --git a/yum/yumRepo.py b/yum/yumRepo.py
index 4f5f7a6..09b2534 100644
--- a/yum/yumRepo.py
+++ b/yum/yumRepo.py
@@ -1068,7 +1068,7 @@ Insufficient space in download directory %s
             self._metadataCurrent = False
         return self._metadataCurrent
 
-    def withinCacheAge(self, myfile, expiration_time):
+    def withinCacheAge(self, myfile, expiration_time, expire_req_filter=True):
         """check if any file is older than a certain amount of time. Used for
            the cachecookie and the mirrorlist
            return True if w/i the expiration time limit
@@ -1078,6 +1078,24 @@ Insufficient space in download directory %s
            file. If any of them are newer then invalidate the cache
            """
 
+        # Never/write means we just skip this...
+        if (expire_req_filter and hasattr(self, '_metadata_cache_req') and
+            self._metadata_cache_req.startswith("read-only:") and
+            self.metadata_expire_filter.startswith("read-only:")):
+
+            cache_filt = self.metadata_expire_filter[len("read-only:"):]
+            cache_req  = self._metadata_cache_req[len("read-only:"):]
+
+            if cache_filt == 'future':
+                assert cache_req in ('past', 'present', 'future')
+                expiration_time = -1
+            if cache_filt == 'present':
+                if cache_req in ('past', 'present'):
+                    expiration_time = -1
+            if cache_filt == 'past':
+                if cache_req == 'past':
+                    expiration_time = -1
+
         # -1 is special and should never get refreshed
         if expiration_time == -1 and os.path.exists(myfile):
             return True
@@ -1850,7 +1868,8 @@ Insufficient space in download directory %s
         fo = None
 
         cacheok = False
-        if self.withinCacheAge(self.mirrorlist_file, self.mirrorlist_expire):
+        if self.withinCacheAge(self.mirrorlist_file, self.mirrorlist_expire,
+                               expire_req_filter=False):
             cacheok = True
             fo = open(self.mirrorlist_file, 'r')
             url = 'file://' + self.mirrorlist_file # just to keep self._readMirrorList(fo,url) happy
diff --git a/yumcommands.py b/yumcommands.py
index a2e0b1b..14a1375 100644
--- a/yumcommands.py
+++ b/yumcommands.py
@@ -280,7 +280,35 @@ class YumCommand:
         :return: True if a transaction set is needed, False otherwise
         """
         return True
+
+    #  Some of this is subjective, esp. between past/present, but roughly use:
+    #
+    # write = I'm using package data to alter the rpmdb in anyway.
+    # read-only:future  = I'm providing data that is likely to result in a
+    #                     future write, so we might as well do it now.
+    #                     Eg. yum check-update && yum update -q -y
+    # read-only:present = I'm providing data about the present state of
+    #                     packages in the repo.
+    #                     Eg. yum list yum
+    # read-only:past    = I'm providing context data about past writes, or just
+    #                     anything that is available is good enough for me
+    #                     (speed is much better than quality).
+    #                     Eg. yum history info
+    #                     Eg. TAB completion
+    #
+    # ...default is write, which does the same thing we always did (obey
+    # metadata_expire and live with it).
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'write'
         
+
 class InstallCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
     install command.
@@ -648,6 +676,19 @@ class InfoCommand(YumCommand):
         
         return True
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        if len(extcmds) and extcmds[0] in ('updates', 'obsoletes'):
+            return 'read-only:future'
+        return 'read-only:present'
+
+
 class ListCommand(InfoCommand):
     """A class containing methods needed by the cli to execute the
     list command.
@@ -1349,6 +1390,17 @@ class ProvidesCommand(YumCommand):
         except yum.Errors.YumBaseError, e:
             return 1, [exception2msg(e)]
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:past'
+
+
 class CheckUpdateCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
     check-update command.
@@ -1440,6 +1492,17 @@ class CheckUpdateCommand(YumCommand):
         else:
             return result, []
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:future'
+
+
 class SearchCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
     search command.
@@ -1508,6 +1571,17 @@ class SearchCommand(YumCommand):
         """
         return False
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:present'
+
+
 class UpgradeCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
     upgrade command.
@@ -1698,6 +1772,17 @@ class ResolveDepCommand(YumCommand):
         except yum.Errors.YumBaseError, e:
             return 1, [exception2msg(e)]
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:past'
+
+
 class ShellCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
     shell command.
@@ -1825,6 +1910,16 @@ class DepListCommand(YumCommand):
         except yum.Errors.YumBaseError, e:
             return 1, [exception2msg(e)]
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:past' # read-only ?
+
 
 class RepoListCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
@@ -2141,6 +2236,16 @@ class RepoListCommand(YumCommand):
         """
         return False
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:past'
+
 
 class HelpCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
@@ -2583,6 +2688,16 @@ class VersionCommand(YumCommand):
             return True
         return vcmd in ('available', 'all', 'group-available', 'group-all')
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        return 'read-only:present'
+
 
 class HistoryCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
@@ -2821,6 +2936,21 @@ class HistoryCommand(YumCommand):
             vcmd = extcmds[0]
         return vcmd in ('repeat', 'redo', 'undo', 'rollback')
 
+    def cacheRequirement(self, base, basecmd, extcmds):
+        """Return the cache requirements for the remote repos.
+
+        :param base: a :class:`yum.Yumbase` object
+        :param basecmd: the name of the command
+        :param extcmds: a list of arguments passed to *basecmd*
+        :return: Type of requirement: read-only:past, read-only:present, read-only:future, write
+        """
+        vcmd = 'list'
+        if extcmds:
+            vcmd = extcmds[0]
+        if vcmd in ('repeat', 'redo', 'undo', 'rollback'):
+            return 'write'
+        return 'read-only:past'
+
 
 class CheckRpmdbCommand(YumCommand):
     """A class containing methods needed by the cli to execute the
-- 
1.7.6.5



More information about the Yum-devel mailing list