From bf4dc1cd37acfdf32c9d70531914bd58f06bbd84 Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Fri, 11 Feb 2011 19:06:22 +0100 Subject: [PATCH] [entropy.graph] implement Graph.destroy() to free circular references (was causing interesting memleak) --- client/text_query.py | 2 + libraries/entropy/client/interfaces/dep.py | 5 ++ libraries/entropy/graph.py | 75 ++++++++++++++++++++++ 3 files changed, 82 insertions(+) diff --git a/client/text_query.py b/client/text_query.py index 4ccb53d08..dba292c03 100644 --- a/client/text_query.py +++ b/client/text_query.py @@ -385,6 +385,7 @@ def _revgraph_package(installed_pkg_id, package, dbconn, show_complete = False): _show_graph_legend() del stack + graph.destroy() del graph return 0 @@ -471,6 +472,7 @@ def _graph_package(match, package, entropy_intf, show_complete = False): _show_dependencies_legend() del stack + graph.destroy() del graph return 0 diff --git a/libraries/entropy/client/interfaces/dep.py b/libraries/entropy/client/interfaces/dep.py index 182453f3e..0aee6a778 100644 --- a/libraries/entropy/client/interfaces/dep.py +++ b/libraries/entropy/client/interfaces/dep.py @@ -1334,12 +1334,14 @@ class CalculatorsMixin: deptree_conflicts |= conflicts if deps_not_found: + graph.destroy() del graph raise DependenciesNotFound(deps_not_found) # solve depgraph and append conflicts deptree = graph.solve() if 0 in deptree: + graph.destroy() del graph raise KeyError("Graph contains a dep_level == 0") @@ -1354,6 +1356,7 @@ class CalculatorsMixin: _colliding_deps = [x for x in _dup_deps_collisions.values() if \ len(x) > 1] if _colliding_deps: + graph.destroy() del graph raise DependenciesCollision(_colliding_deps) @@ -1364,6 +1367,7 @@ class CalculatorsMixin: level_count += 1 reverse_tree[level_count] = deptree[key] + graph.destroy() del deptree, graph reverse_tree[0] = deptree_conflicts @@ -1660,6 +1664,7 @@ class CalculatorsMixin: deptree = graph.solve() del flat_dep_tree + graph.destroy() del graph if self.xcache: diff --git a/libraries/entropy/graph.py b/libraries/entropy/graph.py index 0465b795f..ae1308db5 100644 --- a/libraries/entropy/graph.py +++ b/libraries/entropy/graph.py @@ -35,6 +35,25 @@ class GraphNode(object): self.__item = item self.__arches = set() + def __del__(self): + try: + self._clear() + except (NameError, AttributeError): + pass + + def _clear(self): + """ + Clear the object + """ + try: + self.__arches.clear() + except (NameError, AttributeError): + pass + try: + self.__item = None + except (NameError, AttributeError): + pass + def __str__(self): """ Default string representation. @@ -135,6 +154,22 @@ class GraphArchSet(object): self.__origin = starting_point self.__endpoints = set() + def __del__(self): + try: + self._clear() + except (NameError, AttributeError): + pass + + def _clear(self): + """ + Cleanup the object + """ + try: + self.__endpoints.clear() + del self.__origin + except (NameError, AttributeError): + pass + def __str__(self): """ Default string representation. @@ -210,6 +245,16 @@ class TopologicalSorter(object): self.__adjacency_map = adjacency_map self.__stack = Lifo() + def __del__(self): + try: + self.__adjacency_map.clear() + except (NameError, AttributeError): + pass + try: + self.__stack.clear() + except (NameError, AttributeError): + pass + def __topological_sort_visit_node(self, node, low, result): """ Internal method, visits a node ad push to stack. @@ -340,6 +385,36 @@ class Graph(object): self.__archs_map = {} self.__graph_map_cache = None + def __del__(self): + try: + self.destroy() + except (AttributeError, NameError): + pass + + def destroy(self): + """ + Cleanup any reference. + """ + try: + for obj in self.__graph.values(): + obj._clear() + self.__graph.clear() + except (NameError, AttributeError): + pass + try: + for obj in self.__archs_map.values(): + obj._clear() + self.__archs_map.clear() + except (NameError, AttributeError): + pass + try: + if self.__graph_map_cache is not None: + for obj in self.__graph_map_cache.values(): + obj._clear() + self.__graph_map_cache.clear() + except (NameError, AttributeError): + pass + def __invalidate_cache(self): """ Private method, stay away from here.