Make generic C++ decorator for handling SA_AIS_ERR_TRY_AGAIN return code
of AIS APIs.
---
src/ais/Makefile.am | 5 +-
src/ais/try_again_decorator.h | 110 +++++++++++++++++++++++++++++
src/base/Makefile.am | 4 +-
src/base/tests/try_again_decorator_test.cc | 69 ++++++++++++++++++
4 files changed, 185 insertions(+), 3 deletions(-)
create mode 100644 src/ais/try_again_decorator.h
create mode 100644 src/base/tests/try_again_decorator_test.cc
diff --git a/src/ais/Makefile.am b/src/ais/Makefile.am
index 77ea2d8..50e4cb6 100644
--- a/src/ais/Makefile.am
+++ b/src/ais/Makefile.am
@@ -12,7 +12,7 @@
# licensing terms.
#
-CORE_INCLUDES += -I$(top_srcdir)/src/ais/include
+CORE_INCLUDES += -I$(top_srcdir)/src/ais/include -I$(top_srcdir)/src/ais
EXTRA_DIST += \
src/ais/lib/libSaAmf.map \
@@ -54,7 +54,8 @@ include_HEADERS += \
src/ais/include/saMsg.h \
src/ais/include/saNtf.h \
src/ais/include/saPlm.h \
- src/ais/include/saSmf.h
+ src/ais/include/saSmf.h \
+ src/ais/try_again_decorator.h
pkgconfig_DATA += \
src/ais/lib/opensaf-amf.pc \
diff --git a/src/ais/try_again_decorator.h b/src/ais/try_again_decorator.h
new file mode 100644
index 0000000..19606f0
--- /dev/null
+++ b/src/ais/try_again_decorator.h
@@ -0,0 +1,110 @@
+/* -*- OpenSAF -*-
+ *
+ * Copyright Ericsson AB 2017 - All Rights Reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ */
+
+#ifndef AIS_TRY_AGAIN_DECORATOR_H_
+#define AIS_TRY_AGAIN_DECORATOR_H_
+
+#include <iostream>
+#include <functional>
+#include <saAis.h>
+#include "base/time.h"
+
+namespace base {
+
+//>
+// C++ decorator which escapsulates try again handling.
+//
+// E.g:
+// 1) If user wants to call saClmInitialize() which has try again
+// handling inside using this decorator, do this:
+//
+// auto saClmInitialize = base::make_decorator(::saClmInitialize);
+// if (saClmInitialize(handle, cbs, version) != SA_AIS_OK) {
+// // error handling
+// }
+//
+// 2) If user wants using other retry control policy than default ones,
+// then define your own policy like below. The best way is copy the default
+// policy, then modify to your own values.
+//
+// class MyOwnTryAgain {
+// public:
+// constexpr static bool is_ais_code_accepted(SaAisErrorT code) {
+// return (code != SA_AIS_ERR_TRY_AGAIN && code != SA_AIS_ERR_UNAVAILABLE);
+// }
+//
+// public:
+// constexpr static uint64_t interval_ms = 10;
+// constexpr static uint64_t timeout_ms = 10 * 1000;
+// };
+//
+// using MyOwnPolicy = base::UseMyPolicy<MyOwnPolicy>;
+// auto saClmInitialize = MyOwnPolicy::make_decorator(::saClmInitialize);
+// if (saClmInitialize(handle, cbs, version) != SA_AIS_OK) {
+// // error handling
+// }
+//
+//<
+
+class DefaultRetryPolicy {
+ public:
+ // Which error code you want to do the retry.
+ constexpr static bool is_ais_code_accepted(SaAisErrorT code) {
+ return (code != SA_AIS_ERR_TRY_AGAIN);
+ }
+
+ public:
+ // Sleep time between retries (ms)
+ constexpr static uint64_t interval_ms = 40;
+ // Timeout for the retry (ms)
+ constexpr static uint64_t timeout_ms = 10 * 1000ull;
+};
+
+template <class T, class Policy = DefaultRetryPolicy> class Decorator;
+template <class T, class Policy, class... Args>
+class Decorator<T(Args ...), Policy> {
+ public:
+ explicit Decorator(const std::function<T(Args ...)>& f) : f_{f} {}
+ T operator()(Args ... args) {
+ T ais_error = SA_AIS_OK;
+ base::Timer wtime(Policy::timeout_ms);
+ while (wtime.is_timeout() == false) {
+ ais_error = f_(args...);
+ if (Policy::is_ais_code_accepted(ais_error) == true) break;
+ base::Sleep({0, Policy::interval_ms * 1000 * 1000ull});
+ }
+ return ais_error;
+ }
+
+ private:
+ const std::function<T(Args ...)> f_;
+};
+
+template<class T, class... Args>
+Decorator<T(Args...)> make_decorator(T (*f)(Args ...)) {
+ return Decorator<T(Args...)>(std::function<T(Args...)>(f));
+}
+
+template <class Policy>
+class UseMyPolicy {
+ public:
+ template<class T, class... Args>
+ static Decorator<T(Args...), Policy> make_decorator(T (*f)(Args ...)) {
+ return Decorator<T(Args...), Policy>(std::function<T(Args...)>(f));
+ }
+};
+} // namespace base
+
+#endif //< AIS_TRY_AGAIN_DECORATOR_H_
diff --git a/src/base/Makefile.am b/src/base/Makefile.am
index 956cce6..feafdde 100644
--- a/src/base/Makefile.am
+++ b/src/base/Makefile.am
@@ -208,7 +208,9 @@ bin_libbase_test_SOURCES = \
src/base/tests/time_compare_test.cc \
src/base/tests/time_convert_test.cc \
src/base/tests/time_subtract_test.cc \
- src/base/tests/unix_socket_test.cc
+ src/base/tests/unix_socket_test.cc \
+ src/base/tests/try_again_decorator_test.cc
+
bin_libbase_test_LDADD = \
$(GTEST_DIR)/lib/libgtest.la \
diff --git a/src/base/tests/try_again_decorator_test.cc
b/src/base/tests/try_again_decorator_test.cc
new file mode 100644
index 0000000..921991d
--- /dev/null
+++ b/src/base/tests/try_again_decorator_test.cc
@@ -0,0 +1,69 @@
+/* -*- OpenSAF -*-
+ *
+ * (C) Copyright 2017 The OpenSAF Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
+ * under the GNU Lesser General Public License Version 2.1, February 1999.
+ * The complete license can be accessed from the following location:
+ * http://opensource.org/licenses/lgpl-license.php
+ * See the Copying file included with the OpenSAF distribution for full
+ * licensing terms.
+ *
+ * Author(s): Ericsson AB
+ *
+ */
+
+#include <try_again_decorator.h>
+#include "gtest/gtest.h"
+
+namespace {
+unsigned counter = 0;
+};
+
+extern "C" SaAisErrorT TestMethod() {
+ ++counter;
+ return SA_AIS_ERR_TRY_AGAIN;
+}
+
+extern "C" SaAisErrorT TestOtherMethod() {
+ ++counter;
+ return (counter % 2 ) ? SA_AIS_ERR_TRY_AGAIN : SA_AIS_ERR_UNAVAILABLE;
+}
+
+TEST(make_decorator, DefaultControl) {
+ // default interval = 40ms, timeout = 10 * 1000ms
+ auto DecorTestMethod = base::make_decorator(::TestMethod);
+
+ EXPECT_EQ(DecorTestMethod(), SA_AIS_ERR_TRY_AGAIN);
+ EXPECT_GE(counter, 200);
+ EXPECT_LE(counter, 250);
+ counter = 0;
+}
+
+class MyTryAgain {
+ public:
+ constexpr static bool is_ais_code_accepted(SaAisErrorT code) {
+ return (code != SA_AIS_ERR_TRY_AGAIN && code != SA_AIS_ERR_UNAVAILABLE);
+ }
+
+ public:
+ constexpr static uint64_t interval_ms = 10;
+ constexpr static uint64_t timeout_ms = 100;
+};
+
+TEST(make_decorator, GivenRetryControl) {
+ counter = 0;
+ using MyPolicy = base::UseMyPolicy<MyTryAgain>;
+ auto DecorTestMethod = MyPolicy::make_decorator(::TestOtherMethod);
+
+ if (counter % 2) {
+ EXPECT_EQ(DecorTestMethod(), SA_AIS_ERR_TRY_AGAIN);
+ } else {
+ EXPECT_EQ(DecorTestMethod(), SA_AIS_ERR_UNAVAILABLE);
+ }
+ EXPECT_GE(counter, 5);
+ EXPECT_LE(counter, 10);
+ counter = 0;
+}
--
1.9.1
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel