From 4a8d1703d4d1522abafc52b643e249e8a830007f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yannig=20Perr=C3=A9?= Date: Mon, 2 Nov 2015 21:04:20 +0100 Subject: [PATCH] New patch against hostvars.py. With this patch, Ansible run lose 50% of time. Little rewrite of previous patch to use sha1 signature. Use fail_on_undefined to compute sha1 signature. --- lib/ansible/template/__init__.py | 18 +++++++++++++----- lib/ansible/vars/hostvars.py | 18 ++++++++++++++++-- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/ansible/template/__init__.py b/lib/ansible/template/__init__.py index eded032c7cc..1f41fcee7b1 100644 --- a/lib/ansible/template/__init__.py +++ b/lib/ansible/template/__init__.py @@ -39,6 +39,11 @@ from ansible.template.template import AnsibleJ2Template from ansible.template.vars import AnsibleJ2Vars from ansible.utils.debug import debug +try: + from hashlib import sha1 +except ImportError: + from sha import sha as sha1 + from numbers import Number __all__ = ['Templar'] @@ -270,6 +275,9 @@ class Templar: before being sent through the template engine. ''' + if fail_on_undefined is None: + fail_on_undefined = self._fail_on_undefined_errors + # Don't template unsafe variables, instead drop them back down to # their constituent type. if hasattr(variable, '__UNSAFE__'): @@ -302,10 +310,10 @@ class Templar: return C.DEFAULT_NULL_REPRESENTATION # Using a cache in order to prevent template calls with already templated variables - cache_key = variable + str(preserve_trailing_newlines) + str(escape_backslashes) + str(overrides) - try: - result = self._cached_result[cache_key] - except KeyError: + sha1_hash = sha1(variable + str(preserve_trailing_newlines) + str(escape_backslashes) + str(fail_on_undefined) + str(overrides)).hexdigest() + if sha1_hash in self._cached_result: + result = self._cached_result[sha1_hash] + else: result = self._do_template(variable, preserve_trailing_newlines=preserve_trailing_newlines, escape_backslashes=escape_backslashes, fail_on_undefined=fail_on_undefined, overrides=overrides) if convert_data: # if this looks like a dictionary or list, convert it to such using the safe_eval method @@ -317,7 +325,7 @@ class Templar: else: # FIXME: if the safe_eval raised an error, should we do something with it? pass - self._cached_result[cache_key] = result + self._cached_result[sha1_hash] = result #return self._clean_data(result) diff --git a/lib/ansible/vars/hostvars.py b/lib/ansible/vars/hostvars.py index 9f83342be3e..ff7fa84fb6c 100644 --- a/lib/ansible/vars/hostvars.py +++ b/lib/ansible/vars/hostvars.py @@ -28,6 +28,11 @@ from ansible import constants as C from ansible.inventory.host import Host from ansible.template import Templar +try: + from hashlib import sha1 +except ImportError: + from sha import sha as sha1 + __all__ = ['HostVars'] # Note -- this is a Mapping, not a MutableMapping @@ -39,6 +44,7 @@ class HostVars(collections.Mapping): self._loader = loader self._play = play self._variable_manager = variable_manager + self._cached_result = {} hosts = inventory.get_hosts(ignore_limits_and_restrictions=True) @@ -68,8 +74,16 @@ class HostVars(collections.Mapping): host = self._lookup.get(host_name) data = self._variable_manager.get_vars(loader=self._loader, host=host, play=self._play, include_hostvars=False) - templar = Templar(variables=data, loader=self._loader) - return templar.template(data, fail_on_undefined=False) + + # Using cache in order to avoid template call + sha1_hash = sha1(str(data)).hexdigest() + if sha1_hash in self._cached_result: + result = self._cached_result[sha1_hash] + else: + templar = Templar(variables=data, loader=self._loader) + result = templar.template(data, fail_on_undefined=False) + self._cached_result[sha1_hash] = result + return result def __contains__(self, host_name): item = self.get(host_name)