From 60300b014952f5b2fa4c2a9010876f5b871f0f66 Mon Sep 17 00:00:00 2001 From: Zane Bitter Date: Fri, 15 May 2015 17:18:12 -0400 Subject: [PATCH] Get rid of circular references in Resource and Function Circular references cause practically every bit of data that Heat uses to remain in memory until the completion of an operation, and even then to only be freed once the loop is detected by the garbage collector. By breaking all of the loops using weak references, we can ensure that things will get freed when they are no longer referenced without the need to wait for garbage collection (which should also take a lot less time). This change removes the loops from Resource and Function objects back to the Stack. Change-Id: Ibf80e95e69a2f27ed29754a2e0f1125e8eed0775 Closes-Bug: #1454873 --- heat/engine/function.py | 13 ++++++++++++- heat/engine/resource.py | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/heat/engine/function.py b/heat/engine/function.py index 2ceaf95e2a..dfac156b3c 100644 --- a/heat/engine/function.py +++ b/heat/engine/function.py @@ -14,6 +14,7 @@ import abc import collections import itertools +import weakref import six @@ -33,10 +34,20 @@ class Function(object): { : } """ super(Function, self).__init__() - self.stack = stack + self._stackref = weakref.ref(stack) if stack is not None else None self.fn_name = fn_name self.args = args + @property + def stack(self): + ref = self._stackref + if ref is None: + return None + + stack = ref() + assert stack is not None, "Need a reference to the Stack object" + return stack + def validate(self): """ Validate arguments without resolving the function. diff --git a/heat/engine/resource.py b/heat/engine/resource.py index 10489b1fec..b8a74d77c5 100644 --- a/heat/engine/resource.py +++ b/heat/engine/resource.py @@ -15,6 +15,7 @@ import base64 import contextlib import datetime as dt import warnings +import weakref from oslo_config import cfg from oslo_log import log as logging @@ -218,6 +219,16 @@ class Resource(object): self.replaced_by = resource.replaced_by self.current_template_id = resource.current_template_id + @property + def stack(self): + stack = self._stackref() + assert stack is not None, "Need a reference to the Stack object" + return stack + + @stack.setter + def stack(self, stack): + self._stackref = weakref.ref(stack) + def reparse(self): self.properties = self.t.properties(self.properties_schema, self.context)