From 6589d4db658073c411c1e9e419e7770d45ed0a66 Mon Sep 17 00:00:00 2001 From: Timo Tietavainen Date: Tue, 9 Mar 2021 14:37:14 +0200 Subject: [PATCH] Take DBAAS multi-channel publishing Redis modules into use Following SDL APIs are defined so that multiple channel-event pairs can be given as function argument but actual SDL implementation utilized such a DBAAS (Redis) module what expect to get only one channel-event pair. Fix the implementation of these SDL APIs to use the correct DBAAS module what support multiple channel-event pairs: * set_if_and_publish() * set_if_not_exists_and_publish() * remove_if_and_publish() Please note that in runtime environment DBAAS service needs to run on DBAAS image version 0.4.0 or newer. Older images do not have multiple channel-event pairs support as a Redis module. Updated also start_event_listener() and handle_events() description to emphasize that channel-event subscription must be done before calling those functions, otherwise open-source Redis client application could throw an exception due to not having any subscription when it receives some event, for example a ping event in case of the DBAAS Sentinel deployment. Issue-ID: RIC-758 Signed-off-by: Timo Tietavainen Change-Id: I75d4e3316d7387b7a1a735fe3eb357de7ef794bb --- docs/release-notes.rst | 4 ++++ ricsdl-package/README.md | 6 +++++- ricsdl-package/examples/notify.py | 15 +++++++-------- ricsdl-package/examples/sync.py | 8 ++++---- ricsdl-package/ricsdl/__init__.py | 2 +- ricsdl-package/ricsdl/backend/redis.py | 8 ++++---- ricsdl-package/ricsdl/syncstorage_abc.py | 8 ++++++++ ricsdl-package/tests/backend/test_redis.py | 12 ++++++------ 8 files changed, 39 insertions(+), 24 deletions(-) mode change 100644 => 100755 ricsdl-package/examples/sync.py diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 2e04473..496254c 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -33,6 +33,10 @@ This document provides the release notes of the ricsdl library. Version history --------------- +[2.1.1] - 2021-03-09 + +* Take DBAAS multi-channel publishing Redis modules into use. + [2.1.0] - 2020-08-26 * Add support for notifications diff --git a/ricsdl-package/README.md b/ricsdl-package/README.md index d32c8b4..621047e 100755 --- a/ricsdl-package/README.md +++ b/ricsdl-package/README.md @@ -37,7 +37,11 @@ database is used as a backend data storage solution. Notifications -Notifications functionality provide SDL clients the possibility to receive notifications about data changes in SDL namespaces. SDL client receiving notifications about data changes is referred to as "subscriber", while the SDL client modifying data and publishing notifications is referred to as "publisher". +Notifications functionality provide SDL clients the possibility to receive +notifications about data changes in SDL namespaces. SDL client receiving +notifications about data changes is referred to as "subscriber", while the SDL +client modifying data and publishing notifications is referred to as +"publisher". Install ------- diff --git a/ricsdl-package/examples/notify.py b/ricsdl-package/examples/notify.py index 7d2f203..3041d80 100755 --- a/ricsdl-package/examples/notify.py +++ b/ricsdl-package/examples/notify.py @@ -23,11 +23,11 @@ Execution of these examples requires: * Following Redis extension commands have been installed to runtime environment: - MSETPUB - SETIE - - SETIEPUB - - SETNXPUB - - DELPUB + - SETIEMPUB + - SETNXMPUB + - DELMPUB - DELIE - - DELIEPUB + - DELIEMPUB Redis v4.0 or greater is required. Older versions do not support extension modules. Implementation of above commands is produced by RIC DBaaS: https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/dbaas @@ -134,6 +134,9 @@ def listen_thread(): pass time.sleep(0.001) +# Subscribe to MY_CHANNEL. We expect that anytime we receive a message in the +# channel, cb function will be called. +_try_func_return(lambda: mysdl.subscribe_channel(MY_NS, cb, MY_CHANNEL)) # As mentioned above, there are two available methods for applications to # handle notifications @@ -143,10 +146,6 @@ else: thread = threading.Thread(target=listen_thread) thread.start() -# Subscribe to MY_CHANNEL. We expect that anytime we receive a message in the -# channel, cb function will be called. -_try_func_return(lambda: mysdl.subscribe_channel(MY_NS, cb, MY_CHANNEL)) - # Sets a value 'my_value' for a key 'my_key' under given namespace. Note that value # type must be bytes and multiple key values can be set in one set function call. _try_func_callback_return( diff --git a/ricsdl-package/examples/sync.py b/ricsdl-package/examples/sync.py old mode 100644 new mode 100755 index 6ea9ef9..1fa5742 --- a/ricsdl-package/examples/sync.py +++ b/ricsdl-package/examples/sync.py @@ -25,11 +25,11 @@ Execution of these examples requires: * Following Redis extension commands have been installed to runtime environment: - MSETPUB - SETIE - - SETIEPUB - - SETNXPUB - - DELPUB + - SETIEMPUB + - SETNXMPUB + - DELMPUB - DELIE - - DELIEPUB + - DELIEMPUB Redis v4.0 or greater is required. Older versions do not support extension modules. Implementation of above commands is produced by RIC DBaaS: https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/dbaas diff --git a/ricsdl-package/ricsdl/__init__.py b/ricsdl-package/ricsdl/__init__.py index df7e9c2..b4c587c 100644 --- a/ricsdl-package/ricsdl/__init__.py +++ b/ricsdl-package/ricsdl/__init__.py @@ -31,7 +31,7 @@ from .exceptions import ( ) -__version__ = '2.1.0' +__version__ = '2.1.1' __all__ = [ diff --git a/ricsdl-package/ricsdl/backend/redis.py b/ricsdl-package/ricsdl/backend/redis.py index c67be2d..c319bf0 100755 --- a/ricsdl-package/ricsdl/backend/redis.py +++ b/ricsdl-package/ricsdl/backend/redis.py @@ -205,7 +205,7 @@ class RedisBackend(DbBackendAbc): values = self.__redis.mget(db_keys) for idx, val in enumerate(values): # return only key values, which has a value - if val: + if val is not None: ret[keys[idx]] = val return ret @@ -285,7 +285,7 @@ class RedisBackend(DbBackendAbc): channels_and_events_prepared = [] channels_and_events_prepared, _ = self._prepare_channels(ns, channels_and_events) with _map_to_sdl_exception(): - ret = self.__redis.execute_command("SETIEPUB", db_key, new_data, old_data, + ret = self.__redis.execute_command("SETIEMPUB", db_key, new_data, old_data, *channels_and_events_prepared) return ret == b"OK" @@ -294,7 +294,7 @@ class RedisBackend(DbBackendAbc): db_key = self._add_key_ns_prefix(ns, key) channels_and_events_prepared, _ = self._prepare_channels(ns, channels_and_events) with _map_to_sdl_exception(): - ret = self.__redis.execute_command("SETNXPUB", db_key, data, + ret = self.__redis.execute_command("SETNXMPUB", db_key, data, *channels_and_events_prepared) return ret == b"OK" @@ -316,7 +316,7 @@ class RedisBackend(DbBackendAbc): db_key = self._add_key_ns_prefix(ns, key) channels_and_events_prepared, _ = self._prepare_channels(ns, channels_and_events) with _map_to_sdl_exception(): - ret = self.__redis.execute_command("DELIEPUB", db_key, data, + ret = self.__redis.execute_command("DELIEMPUB", db_key, data, *channels_and_events_prepared) return bool(ret) diff --git a/ricsdl-package/ricsdl/syncstorage_abc.py b/ricsdl-package/ricsdl/syncstorage_abc.py index 2c58e37..61dd67f 100755 --- a/ricsdl-package/ricsdl/syncstorage_abc.py +++ b/ricsdl-package/ricsdl/syncstorage_abc.py @@ -896,6 +896,10 @@ class SyncStorageAbc(ABC): events from subscriptions. The registered callback function will be called when an event is received. + It should be noted that subscribe_channel must be called before calling + start_event_listener to do at least one subscription before event loop + starts. + Raises: SdlTypeError: If function's argument is of an inappropriate type. NotConnected: If SDL is not connected to the backend data storage. @@ -915,6 +919,10 @@ class SyncStorageAbc(ABC): event loop. Calling this function after start_event_listener raises an exception. If there are no notifications, these returns None. + It should be noted that subscribe_channel must be called before calling of the + handle_events in an event loop. At least one subscription must be done before + events handling starts. + Returns: Tuple: (channel: str, message: str) diff --git a/ricsdl-package/tests/backend/test_redis.py b/ricsdl-package/tests/backend/test_redis.py index 29cb582..c5e1b03 100755 --- a/ricsdl-package/tests/backend/test_redis.py +++ b/ricsdl-package/tests/backend/test_redis.py @@ -340,7 +340,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = b"OK" ret = self.db.set_if_and_publish(self.ns, self.channels_and_events, self.key, self.old_data, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('SETIEPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('SETIEMPUB', self.key_redis, self.new_data, self.old_data, *self.channels_and_events_redis) assert ret is True @@ -349,7 +349,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = None ret = self.db.set_if_and_publish(self.ns, self.channels_and_events, self.key, self.old_data, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('SETIEPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('SETIEMPUB', self.key_redis, self.new_data, self.old_data, *self.channels_and_events_redis) assert ret is False @@ -364,7 +364,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = b"OK" ret = self.db.set_if_not_exists_and_publish(self.ns, self.channels_and_events, self.key, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('SETNXPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('SETNXMPUB', self.key_redis, self.new_data, *self.channels_and_events_redis) assert ret is True @@ -373,7 +373,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = None ret = self.db.set_if_not_exists_and_publish(self.ns, self.channels_and_events, self.key, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('SETNXPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('SETNXMPUB', self.key_redis, self.new_data, *self.channels_and_events_redis) assert ret is False @@ -395,7 +395,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = 1 ret = self.db.remove_if_and_publish(self.ns, self.channels_and_events, self.key, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('DELIEPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('DELIEMPUB', self.key_redis, self.new_data, *self.channels_and_events_redis) assert ret is True @@ -404,7 +404,7 @@ class TestRedisBackend: self.mock_redis.execute_command.return_value = 0 ret = self.db.remove_if_and_publish(self.ns, self.channels_and_events, self.key, self.new_data) - self.mock_redis.execute_command.assert_called_once_with('DELIEPUB', self.key_redis, + self.mock_redis.execute_command.assert_called_once_with('DELIEMPUB', self.key_redis, self.new_data, *self.channels_and_events_redis) assert ret is False -- 2.16.6