close_portdbapi_caches: portage.db atexit hook
authorZac Medico <zmedico@gentoo.org>
Sat, 8 Jun 2013 11:08:47 +0000 (04:08 -0700)
committerZac Medico <zmedico@gentoo.org>
Sat, 8 Jun 2013 11:08:47 +0000 (04:08 -0700)
The python interpreter does _not_ guarantee that destructors are
called for objects that remain when the interpreter exits, so we
use an atexit hook to call destructors for any global portdbapi
instances that may have been constructed.

pym/portage/dbapi/porttree.py
pym/portage/tests/resolver/ResolverPlayground.py

index b106de779dccb527b2f8a82c3c177a046b9d5859..fc3fc03969efe56060d6b115fac06f49f4fe08dc 100644 (file)
@@ -53,6 +53,39 @@ if sys.hexversion >= 0x3000000:
        basestring = str
        long = int
 
+def close_portdbapi_caches():
+       # The python interpreter does _not_ guarantee that destructors are
+       # called for objects that remain when the interpreter exits, so we
+       # use an atexit hook to call destructors for any global portdbapi
+       # instances that may have been constructed.
+       try:
+               portage._legacy_globals_constructed
+       except AttributeError:
+               pass
+       else:
+               if "db" in portage._legacy_globals_constructed:
+                       try:
+                               db = portage.db
+                       except AttributeError:
+                               pass
+                       else:
+                               if isinstance(db, dict):
+                                       for x in db.values():
+                                               try:
+                                                       if "porttree" in x.lazy_items:
+                                                               continue
+                                               except (AttributeError, TypeError):
+                                                       continue
+                                               try:
+                                                       x = x.pop("porttree").dbapi
+                                               except (AttributeError, KeyError):
+                                                       continue
+                                               if not isinstance(x, portdbapi):
+                                                       continue
+                                               x.close_caches()
+
+portage.process.atexit_register(close_portdbapi_caches)
+
 # It used to be necessary for API consumers to remove portdbapi instances
 # from portdbapi_instances, in order to avoid having accumulated instances
 # consume memory. Now, portdbapi_instances is just an empty dummy list, so
@@ -67,10 +100,6 @@ class _dummy_list(list):
                except ValueError:
                        pass
 
-def close_portdbapi_caches():
-       # Since portdbapi_instances is a dummy list, there's nothing to do here.
-       pass
-
 class portdbapi(dbapi):
        """this tree will scan a portage directory located at root (passed to init)"""
        portdbapi_instances = _dummy_list()
index 15ef95da7d543825cd2aa1e680914b90c9d41730..bff4512fed092e8990faa2936ff841a7d2d2d1b7 100644 (file)
@@ -544,6 +544,9 @@ class ResolverPlayground(object):
                                return
 
        def cleanup(self):
+               for eroot in self.trees:
+                       portdb = self.trees[eroot]["porttree"].dbapi
+                       portdb.close_caches()
                if self.debug:
                        print("\nEROOT=%s" % self.eroot)
                else: