1 Star 0 Fork 97

王策/anaconda

forked from src-openEuler/anaconda 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
bugfix-Propagate-a-lazy-proxy-of-the-storage-model.patch 10.05 KB
一键复制 编辑 原始数据 按行查看 历史
From 39d3a894411e3069cdb14354509153028a48e6c5 Mon Sep 17 00:00:00 2001
From: Vendula Poncova <vponcova@redhat.com>
Date: Wed, 2 Sep 2020 13:40:36 +0200
Subject: [PATCH] Propagate a lazy proxy of the storage model
The storage model for the partitioning modules should be always created lazily.
When we reset the partitioning, the new model shouldn't be created until we try
to work with it. Then we create a new copy of the storage model, hide disks that
are not selected and possibly initialize empty disks.
There is a problem with modules that need to be able to work with the same copy
of the storage model as the partitioning modules. At this moment, it is only the
device tree module. The suggested solution is to propagate a lazy proxy of the
storage model. It will not trigger the creation of the copy until we try to
access the attributes of the storage model.
Basically, the device tree module always gets the storage model on demand from
the storage property of the partitioning module.
Related: rhbz#1868577
---
pyanaconda/core/util.py | 37 +++++++
.../modules/storage/partitioning/base.py | 28 ++++--
.../module_part_interactive_test.py | 18 ++++
tests/nosetests/pyanaconda_tests/util_test.py | 97 ++++++++++++++++++-
4 files changed, 170 insertions(+), 10 deletions(-)
diff --git a/pyanaconda/core/util.py b/pyanaconda/core/util.py
index 4615f9fd8..60b6ff310 100644
--- a/pyanaconda/core/util.py
+++ b/pyanaconda/core/util.py
@@ -1431,3 +1431,40 @@ def is_smt_enabled():
except (IOError, ValueError):
log.warning("Failed to detect SMT.")
return False
+
+
+class LazyObject(object):
+ """The lazy object."""
+
+ def __init__(self, getter):
+ """Create a proxy of an object.
+
+ The object might not exist until we call the given
+ function. The function is called only when we try
+ to access the attributes of the object.
+
+ The returned object is not cached in this class.
+ We call the function every time.
+
+ :param getter: a function that returns the object
+ """
+ self._getter = getter
+
+ @property
+ def _object(self):
+ return self._getter()
+
+ def __eq__(self, other):
+ return self._object == other
+
+ def __hash__(self):
+ return self._object.__hash__()
+
+ def __getattr__(self, name):
+ return getattr(self._object, name)
+
+ def __setattr__(self, name, value):
+ if name in ("_getter", ):
+ return super().__setattr__(name, value)
+
+ return setattr(self._object, name, value)
diff --git a/pyanaconda/modules/storage/partitioning/base.py b/pyanaconda/modules/storage/partitioning/base.py
index 989fa0a7b..c8b4b95ac 100644
--- a/pyanaconda/modules/storage/partitioning/base.py
+++ b/pyanaconda/modules/storage/partitioning/base.py
@@ -17,12 +17,13 @@
# License and may only be used or replicated with the express permission of
# Red Hat, Inc.
#
-from abc import abstractmethod, abstractproperty
+from abc import abstractmethod
from blivet.devices import PartitionDevice, TmpFSDevice, LVMLogicalVolumeDevice, \
LVMVolumeGroupDevice, MDRaidArrayDevice, BTRFSDevice
from dasbus.server.publishable import Publishable
+from pyanaconda.core.util import LazyObject
from pyanaconda.modules.common.base.base import KickstartBaseModule
from pyanaconda.modules.common.errors.storage import UnavailableStorageError
from pyanaconda.anaconda_loggers import get_module_logger
@@ -45,7 +46,8 @@ class PartitioningModule(KickstartBaseModule, Publishable):
self._selected_disks = []
self._device_tree_module = None
- @abstractproperty
+ @property
+ @abstractmethod
def partitioning_method(self):
"""Type of the partitioning method."""
return None
@@ -67,8 +69,22 @@ class PartitioningModule(KickstartBaseModule, Publishable):
return self._storage_playground
+ @property
+ def lazy_storage(self):
+ """The lazy storage model.
+
+ Provides a lazy access to the storage model. This property will not
+ trigger a creation of the storage playground. The playground will be
+ created on the first access of the storage attributes.
+ """
+ return LazyObject(lambda: self.storage)
+
def _create_storage_playground(self):
"""Prepare the current storage model for partitioning."""
+ log.debug(
+ "Creating a new storage playground for %s with "
+ "selected disks %s.", self, self._selected_disks
+ )
storage = self._current_storage.copy()
storage.select_disks(self._selected_disks)
return storage
@@ -77,16 +93,10 @@ class PartitioningModule(KickstartBaseModule, Publishable):
"""Update the current storage."""
self._current_storage = storage
- if self._device_tree_module:
- self._device_tree_module.on_storage_changed(self.storage)
-
def on_partitioning_reset(self):
"""Drop the storage playground."""
self._storage_playground = None
- if self._device_tree_module:
- self._device_tree_module.on_storage_changed(self.storage)
-
def on_selected_disks_changed(self, selection):
"""Keep the current disk selection."""
self._selected_disks = selection
@@ -100,7 +110,7 @@ class PartitioningModule(KickstartBaseModule, Publishable):
if not module:
module = self._create_device_tree()
- module.on_storage_changed(self.storage)
+ module.on_storage_changed(self.lazy_storage)
self._device_tree_module = module
return module
diff --git a/tests/nosetests/pyanaconda_tests/module_part_interactive_test.py b/tests/nosetests/pyanaconda_tests/module_part_interactive_test.py
index 13d33feab..32fe589b7 100644
--- a/tests/nosetests/pyanaconda_tests/module_part_interactive_test.py
+++ b/tests/nosetests/pyanaconda_tests/module_part_interactive_test.py
@@ -71,6 +71,24 @@ class InteractivePartitioningInterfaceTestCase(unittest.TestCase):
"""Test Method property."""
self.assertEqual(self.interface.PartitioningMethod, PARTITIONING_METHOD_INTERACTIVE)
+ @patch_dbus_publish_object
+ def lazy_storage_test(self, publisher):
+ """Make sure that the storage playground is created lazily."""
+ self.module.on_storage_changed(create_storage())
+
+ device_tree_module = self.module.get_device_tree()
+ self.assertIsNone(self.module._storage_playground)
+
+ device_tree_module.get_disks()
+ self.assertIsNotNone(self.module._storage_playground)
+
+ self.module.on_partitioning_reset()
+ self.module.on_storage_changed(create_storage())
+ self.assertIsNone(self.module._storage_playground)
+
+ device_tree_module.get_actions()
+ self.assertIsNotNone(self.module._storage_playground)
+
@patch_dbus_publish_object
def get_device_tree_test(self, publisher):
"""Test GetDeviceTree."""
diff --git a/tests/nosetests/pyanaconda_tests/util_test.py b/tests/nosetests/pyanaconda_tests/util_test.py
index 1da8362dc..76f1c4465 100644
--- a/tests/nosetests/pyanaconda_tests/util_test.py
+++ b/tests/nosetests/pyanaconda_tests/util_test.py
@@ -29,7 +29,7 @@ from unittest.mock import Mock, patch
from pyanaconda.errors import ExitError
from pyanaconda.core.process_watchers import WatchProcesses
from pyanaconda.core import util
-from pyanaconda.core.util import synchronized
+from pyanaconda.core.util import synchronized, LazyObject
from pyanaconda.core.configuration.anaconda import conf
from timer import timer
@@ -829,3 +829,98 @@ class MiscTests(unittest.TestCase):
)
self.assertEqual(get_anaconda_version_string(), "1.0")
self.assertEqual(get_anaconda_version_string(build_time_version=True), "1.0-1")
+
+
+class LazyObjectTestCase(unittest.TestCase):
+
+ class Object(object):
+
+ def __init__(self):
+ self._x = 0
+
+ @property
+ def x(self):
+ return self._x
+
+ @x.setter
+ def x(self, value):
+ self._x = value
+
+ def f(self, value):
+ self._x += value
+
+ def setUp(self):
+ self._obj = None
+
+ @property
+ def obj(self):
+ if not self._obj:
+ self._obj = self.Object()
+
+ return self._obj
+
+ @property
+ def lazy_obj(self):
+ return LazyObject(lambda: self.obj)
+
+ def get_set_test(self):
+ self.assertIsNotNone(self.lazy_obj)
+ self.assertIsNone(self._obj)
+
+ self.assertEqual(self.lazy_obj.x, 0)
+ self.assertIsNotNone(self._obj)
+
+ self.obj.x = -10
+ self.assertEqual(self.obj.x, -10)
+ self.assertEqual(self.lazy_obj.x, -10)
+
+ self.lazy_obj.x = 10
+ self.assertEqual(self.obj.x, 10)
+ self.assertEqual(self.lazy_obj.x, 10)
+
+ self.lazy_obj.f(90)
+ self.assertEqual(self.obj.x, 100)
+ self.assertEqual(self.lazy_obj.x, 100)
+
+ def eq_test(self):
+ a = object()
+ lazy_a1 = LazyObject(lambda: a)
+ lazy_a2 = LazyObject(lambda: a)
+
+ self.assertEqual(a, lazy_a1)
+ self.assertEqual(lazy_a1, a)
+
+ self.assertEqual(a, lazy_a2)
+ self.assertEqual(lazy_a2, a)
+
+ self.assertEqual(lazy_a1, lazy_a2)
+ self.assertEqual(lazy_a2, lazy_a1)
+
+ self.assertEqual(lazy_a1, lazy_a1)
+ self.assertEqual(lazy_a2, lazy_a2)
+
+ def neq_test(self):
+ a = object()
+ lazy_a = LazyObject(lambda: a)
+
+ b = object()
+ lazy_b = LazyObject(lambda: b)
+
+ self.assertNotEqual(b, lazy_a)
+ self.assertNotEqual(lazy_a, b)
+
+ self.assertNotEqual(lazy_a, lazy_b)
+ self.assertNotEqual(lazy_b, lazy_a)
+
+ def hash_test(self):
+ a = object()
+ lazy_a1 = LazyObject(lambda: a)
+ lazy_a2 = LazyObject(lambda: a)
+
+ b = object()
+ lazy_b1 = LazyObject(lambda: b)
+ lazy_b2 = LazyObject(lambda: b)
+
+ self.assertEqual({a, lazy_a1, lazy_a2}, {a})
+ self.assertEqual({b, lazy_b1, lazy_b2}, {b})
+ self.assertEqual({lazy_a1, lazy_b2}, {a, b})
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wangce1988/anaconda.git
git@gitee.com:wangce1988/anaconda.git
wangce1988
anaconda
anaconda
master

搜索帮助

D67c1975 1850385 1daf7b77 1850385