From 458e729b26a9457df187413d606e5fd18581c33c Mon Sep 17 00:00:00 2001 From: Ake Sandgren Date: Thu, 28 Sep 2017 16:46:04 +0200 Subject: [PATCH 1/3] Make recursive-unload not generate load storms. Protect the load("module") with isloaded("module") or mode() == "unload" that way we get recursive unload without risking load storms with Lmod. --- easybuild/tools/module_generator.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/easybuild/tools/module_generator.py b/easybuild/tools/module_generator.py index f9d69ef03d..5aaae3007a 100644 --- a/easybuild/tools/module_generator.py +++ b/easybuild/tools/module_generator.py @@ -783,10 +783,12 @@ def load_module(self, mod_name, recursive_unload=False, unload_modules=None): body.append(self.LOAD_TEMPLATE) if build_option('recursive_mod_unload') or recursive_unload: - # not wrapping the 'module load' with an is-loaded guard ensures recursive unloading; - # when "module unload" is called on the module in which the depedency "module load" is present, - # it will get translated to "module unload" - load_statement = body + [''] + # wrapping the 'module load' with an 'is-loaded or mode == unload' + # guard ensures recursive unloading while avoiding load storms, + # when "module unload" is called on the module in which the + # depedency "module load" is present, it will get translated + # to "module unload" + load_statement = [self.conditional_statement('isloaded("%(mod_name)s") or mode() == "unload"', '\n'.join(body), negative=True)] else: load_statement = [self.conditional_statement('isloaded("%(mod_name)s")', '\n'.join(body), negative=True)] From 9779a96ae855fe7b6352fbea5bcbd3bb1052dd85 Mon Sep 17 00:00:00 2001 From: Ake Sandgren Date: Thu, 28 Sep 2017 19:38:32 +0200 Subject: [PATCH 2/3] Split the (recursive-unload/not-recursive-unload) load_statement into guard and actual statement generation. Also add reference to Lmod documentation for this. --- easybuild/tools/module_generator.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/easybuild/tools/module_generator.py b/easybuild/tools/module_generator.py index 5aaae3007a..9a5e4d1eae 100644 --- a/easybuild/tools/module_generator.py +++ b/easybuild/tools/module_generator.py @@ -788,9 +788,11 @@ def load_module(self, mod_name, recursive_unload=False, unload_modules=None): # when "module unload" is called on the module in which the # depedency "module load" is present, it will get translated # to "module unload" - load_statement = [self.conditional_statement('isloaded("%(mod_name)s") or mode() == "unload"', '\n'.join(body), negative=True)] + # see also http://lmod.readthedocs.io/en/latest/210_load_storms.html + load_guard = 'isloaded("%(mod_name)s") or mode() == "unload"' else: - load_statement = [self.conditional_statement('isloaded("%(mod_name)s")', '\n'.join(body), negative=True)] + load_guard = 'isloaded("%(mod_name)s")' + load_statement = [self.conditional_statement(load_guard, '\n'.join(body), negative=True)] return '\n'.join([''] + load_statement) % {'mod_name': mod_name} From 53a620f3048004ae5d640d0bc640262b9af87cdc Mon Sep 17 00:00:00 2001 From: Ake Sandgren Date: Thu, 28 Sep 2017 19:42:12 +0200 Subject: [PATCH 3/3] Update test for recursive-unload to handle the new output. --- test/framework/module_generator.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/framework/module_generator.py b/test/framework/module_generator.py index 988af0f5e8..238498e4b4 100644 --- a/test/framework/module_generator.py +++ b/test/framework/module_generator.py @@ -269,10 +269,13 @@ def test_load(self): ]) self.assertEqual(expected, self.modgen.load_module("mod_name")) - # with recursive unloading: no if isloaded guard + # with recursive unloading: if isloaded guard with unload + # check expected = '\n'.join([ '', - 'load("mod_name")', + 'if not isloaded("mod_name") or mode() == "unload" then', + ' load("mod_name")', + 'end', '', ]) self.assertEqual(expected, self.modgen.load_module("mod_name", recursive_unload=True))