Here's an idea to deal with plugins and such involuntarily dragging
headers into memory, ie the issue referred to here:
http://lists.baseurl.org/pipermail/yum-devel/2011-February/007944.html
http://lists.baseurl.org/pipermail/yum-devel/2011-February/007948.html

Instead of letting the package objects own the header, make them
go through RPMDBPackageSack() for the header. The rpmsack keeps
track of "current" header so successive accesses to a package's header
will be cheap, random access possible but slower. This limits the
number of headers kept in memory to just one, which is a big win
over having potentially hundreds of them loaded at once, and even
that can be easily discarded. This doesn't prevent plugins and such
from forcing headers into memory by making new references to them,
but the occasional h['foo'] access such as in changelog plugin no
longer causes it.

Oh and this isn't really intended for inclusion as is (it seems to
work for me, but I've likely missed some details in the rpmdb caching
and all), consider it more as an idea to discuss + kick around to see
if its actually workable.
---
 yum/rpmsack.py |   37 ++++++++++++++-----------------------
 1 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/yum/rpmsack.py b/yum/rpmsack.py
index 3830339..9a8bd17 100644
--- a/yum/rpmsack.py
+++ b/yum/rpmsack.py
@@ -40,7 +40,6 @@ import yum.depsolve
 class RPMInstalledPackage(YumInstalledPackage):
 
     def __init__(self, rpmhdr, index, rpmdb):
-        self._has_hdr = True
         YumInstalledPackage.__init__(self, rpmhdr, yumdb=rpmdb.yumdb)
         # NOTE: We keep summary/description/url because it doesn't add much
         # and "yum search" uses them all.
@@ -51,29 +50,15 @@ class RPMInstalledPackage(YumInstalledPackage):
         self.idx   = index
         self.rpmdb = rpmdb
 
-        self._has_hdr = False
         del self.hdr
 
-    def _get_hdr(self):
-        # Note that we can't use hasattr(self, 'hdr') or we'll recurse
-        if self._has_hdr:
-            return self.hdr
-
-        ts = self.rpmdb.readOnlyTS()
-        mi = ts.dbMatch(0, self.idx)
-        try:
-            return mi.next()
-        except StopIteration:
-            raise Errors.PackageSackError, 'Rpmdb changed underneath us'
-
     def __getattr__(self, varname):
         # If these existed, then we wouldn't get here...
         # Prevent access of __foo__, _cached_foo etc from loading the header 
         if varname.startswith('_'):
             raise AttributeError, "%s has no attribute %s" % (self, varname)
             
-        self.hdr = val = self._get_hdr()
-        self._has_hdr = True
+        val = self.rpmdb._get_hdr(self.idx)
         if varname != 'hdr':   #  This is unusual, for anything that happens
             val = val[varname] # a lot we should preload at __init__.
                                # Also note that pkg.no_value raises KeyError.
@@ -211,6 +196,7 @@ class RPMDBPackageSack(PackageSackBase):
                                      # most operations so it doesn't leave
                                      # any lingering locks.
         self._cached_rpmdb_mtime = None
+        self._cur_hdr = (None, None)
 
         self._cache = {
             'provides' : { },
@@ -271,6 +257,7 @@ class RPMDBPackageSack(PackageSackBase):
         self._cached_conflicts_data = None
         self.transactionReset() # Should do nothing, but meh...
         self._cached_rpmdb_mtime = None
+        self._cur_hdr = (None, None)
 
     def dropCachedDataPostTransaction(self, txmbrs):
         """ Drop cached data that is assocciated with the given transaction,
@@ -617,14 +604,8 @@ class RPMDBPackageSack(PackageSackBase):
 
                 po = self._makePackageObject(hdr, idx)
                 result[po.pkgid] = po
-                if po._has_hdr:
-                    continue # Unlikely, but, meh...
-
-                po.hdr = hdr
-                po._has_hdr = True
                 po.conflicts
-                po._has_hdr = False
-                del po.hdr
+
             self._cached_conflicts_data = result.values()
 
         return self._cached_conflicts_data
@@ -1169,6 +1150,16 @@ class RPMDBPackageSack(PackageSackBase):
         if self.auto_close:
             self.ts.close()
 
+    def _get_hdr(self, idx):
+        ts = self.readOnlyTS()
+        if idx != self._cur_hdr[1]:
+            mi = ts.dbMatch(0, idx)
+            try:
+                self._cur_hdr = (mi.next(), mi.instance())
+            except StopIteration:
+                raise Errors.PackageSackError, 'Rpmdb changed underneath us'
+        return self._cur_hdr[0]
+
     def _search(self, name=None, epoch=None, ver=None, rel=None, arch=None):
         '''List of matching packages, to zero or more of NEVRA.'''
         if name is not None and name in self._pkgname_fails:
-- 
1.7.4

_______________________________________________
Yum-devel mailing list
[email protected]
http://lists.baseurl.org/mailman/listinfo/yum-devel

Reply via email to