Fixes a deadlock issue when both a model change and a notification of
that change is in the queue.
Change-Id: I76554242b45f90c474fc772572820b9cdde16df2
diff --git a/tests/utests/voltha/core/config/test_config.py b/tests/utests/voltha/core/config/test_config.py
index cb846f5..eda0859 100644
--- a/tests/utests/voltha/core/config/test_config.py
+++ b/tests/utests/voltha/core/config/test_config.py
@@ -561,11 +561,7 @@
data=dumps(MessageToDict(data, True, True))
)
- # TODO: Since the event model is commented out in config_node.py then
- # this line needs to be commented out as well, otherwise unit test
- # will fail, hence the build
- # self.event_mock.assert_called_once_with('model-change-events', event)
- self.assertTrue(True)
+ self.event_mock.assert_called_once_with('model-change-events', event)
def test_remove_event(self):
data = Adapter(
@@ -581,12 +577,7 @@
data=dumps(MessageToDict(data, True, True))
)
- # TODO: Since the event model is commented out in config_node.py then
- # this line needs to be commented out as well, otherwise unit test
- # will fail, hence the build
- # self.event_mock.assert_called_once_with('model-change-events', event)
- self.assertTrue(True)
-
+ self.event_mock.assert_called_once_with('model-change-events', event)
class TestTransactionalLogic(DeepTestsBase):
diff --git a/voltha/core/config/config_node.py b/voltha/core/config/config_node.py
index f679786..56518bb 100644
--- a/voltha/core/config/config_node.py
+++ b/voltha/core/config/config_node.py
@@ -304,18 +304,13 @@
proceed_on_errors=1,
)
-
- # TODO: This fix needs to be investigated/reworked as it causes an
- # extra item to be queued in the main branch. This item does
- # not get consumed, hence preventing any device update on the
- # main branch
- # for change_type, data in change_announcements:
- # self._root.enqueue_callback(
- # self._mk_event_bus().advertise,
- # change_type,
- # data,
- # hash=rev.hash
- # )
+ for change_type, data in change_announcements:
+ self._root.enqueue_notification_callback(
+ self._mk_event_bus().advertise,
+ change_type,
+ data,
+ hash=rev.hash,
+ )
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ add operation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/voltha/core/config/config_root.py b/voltha/core/config/config_root.py
index 012ce75..4b1006d 100644
--- a/voltha/core/config/config_root.py
+++ b/voltha/core/config/config_root.py
@@ -33,7 +33,8 @@
'_kv_store',
'_loading',
'_rev_cls',
- '_deferred_callback_queue'
+ '_deferred_callback_queue',
+ '_notification_deferred_callback_queue'
)
def __init__(self, initial_data, kv_store=None, rev_cls=ConfigRevision):
@@ -45,6 +46,7 @@
rev_cls = PersistedConfigRevision
self._rev_cls = rev_cls
self._deferred_callback_queue = []
+ self._notification_deferred_callback_queue = []
super(ConfigRoot, self).__init__(self, initial_data, False)
@property
@@ -146,11 +148,37 @@
def enqueue_callback(self, func, *args, **kw):
self._deferred_callback_queue.append((func, args, kw))
+ def enqueue_notification_callback(self, func, *args, **kw):
+ """
+ A separate queue is required for notification. Previously, when the
+ notifications were added to the self._deferred_callback_queue there
+ was a deadlock condition where two callbacks were added (one
+ related to the model change and one for the notification related to
+ that model change). Since the model change requires the
+ self._deferred_callback_queue to be empty then there was a deadlock
+ in that scenario. The simple approach to avoid this problem is to
+ have separate queues for model and notification.
+ TODO: Investigate whether there is a need for the
+ self._deferred_callback_queue to handle multiple model events at the same time
+ :param func: callback function
+ :param args: args
+ :param kw: key-value args
+ :return: None
+ """
+ self._notification_deferred_callback_queue.append((func, args, kw))
+
def execute_deferred_callbacks(self):
+ # First process the model-triggered related callbacks
while self._deferred_callback_queue:
func, args, kw = self._deferred_callback_queue.pop(0)
func(*args, **kw)
+ # Execute the notification callbacks
+ while self._notification_deferred_callback_queue:
+ func, args, kw = self._notification_deferred_callback_queue.pop(0)
+ func(*args, **kw)
+
+
# ~~~~~~~~~~~~~~~~ Persistence related ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@classmethod