Make generic C++ decorator for handling SA_AIS_ERR_TRY_AGAIN return code of AIS APIs. --- src/base/Makefile.am | 5 +- src/base/tests/try_again_decorator_test.cc | 48 +++++++++++++ src/base/try_again_decorator.h | 109 +++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 src/base/tests/try_again_decorator_test.cc create mode 100644 src/base/try_again_decorator.h
diff --git a/src/base/Makefile.am b/src/base/Makefile.am index 956cce6..f11b738 100644 --- a/src/base/Makefile.am +++ b/src/base/Makefile.am @@ -150,6 +150,7 @@ noinst_HEADERS += \ src/base/unix_client_socket.h \ src/base/unix_server_socket.h \ src/base/unix_socket.h \ + src/base/try_again_decorator.h \ src/base/usrbuf.h TESTS += bin/testleap bin/libbase_test bin/core_common_test @@ -208,7 +209,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..ac8595d --- /dev/null +++ b/src/base/tests/try_again_decorator_test.cc @@ -0,0 +1,48 @@ +/* -*- 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 "base/try_again_decorator.h" +#include "gtest/gtest.h" + +static unsigned counter = 0; + +SaAisErrorT TestMethod() { + ++counter; + return SA_AIS_ERR_TRY_AGAIN; +} + +TEST(TryAgainDecorator, DefaultRetryControl) { + // default interval = 40ms, timeout = 10 * 1000ms + using DefaultDecorator = base::TryAgainDecorator<>; + auto DecorTestMethod = DefaultDecorator::DecorateFunction(TestMethod); + + DecorTestMethod(); + EXPECT_GE(counter, 200); + EXPECT_LE(counter, 250); + counter = 0; +} + +TEST(TryAgainDecorator, GivenRetryControl) { + // interval = 10ms, timeout = 1000ms + using TryAgainDecorator = base::TryAgainDecorator<10, 1 * 1000>; + auto DecorTestMethod = TryAgainDecorator::DecorateFunction(TestMethod); + + DecorTestMethod(); + EXPECT_GE(counter, 50); + EXPECT_LE(counter, 100); + counter = 0; +} diff --git a/src/base/try_again_decorator.h b/src/base/try_again_decorator.h new file mode 100644 index 0000000..e676697 --- /dev/null +++ b/src/base/try_again_decorator.h @@ -0,0 +1,109 @@ +/* -*- 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 BASE_TRY_AGAIN_DECORATOR_H_ +#define BASE_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: +// +// using TryAgainDecorator = base::TryAgainDecorator<>; +// auto saClmInitialize = TryAgainDecorator(::saClmInitialize); +// if (saClmInitialize(handle, cbs, version) != SA_AIS_OK) { +// // error handling +// } +// +// 2) If user wants other retry control than default ones, +// such as interval = 10ms, timeout = 10second, do this: +// +// using TryAgainDecorator = base::TryAgainDecorator< +// {0, 10 * 1000 * 1000}, +// 10 * 1000 +// > +// auto saClmInitialize = TryAgainDecorator(::saClmInitialize); +// if (saClmInitialize(handle, cbs, version) != SA_AIS_OK) { +// // error handling +// } +// +//< + +// Default sleep time b/w retries {second, ns} +static const timespec kInterval = {0, 40 * 1000 * 1000}; +// Default maximum time for retry loop (ms) +static const uint64_t kTimeout = 10 * 1000; + +struct RetryControl { + RetryControl() : interval(kInterval), timeout(kTimeout) {} + RetryControl(timespec i, uint64_t t) : interval(i), timeout(t) {} + RetryControl(const RetryControl& ctrl) + : interval(ctrl.interval), timeout(ctrl.timeout) {} + + // Sleep time b/w retries + timespec interval; + // Maximum time for retry loop + uint64_t timeout; +}; + +template <class> class Decorator; +template <class T, class... Args> +class Decorator<T(Args ...)> { + public: + explicit Decorator(const std::function<T(Args ...)>& f, + const RetryControl& ctrl) + : f_{f}, retry_ctrl_{ctrl} {} + + explicit Decorator(const std::function<T(Args ...)>& f) : f_{f} {} + + T operator()(Args ... args) { + T ais_error; + base::Timer wtime(retry_ctrl_.timeout); + while (wtime.is_timeout() == false) { + ais_error = f_(args...); + if (ais_error != SA_AIS_ERR_TRY_AGAIN) break; + base::Sleep(retry_ctrl_.interval); + } + return ais_error; + } + + private: + const std::function<T(Args ...)> f_; + RetryControl retry_ctrl_; +}; + +template <uint64_t interval_ms = 40, uint64_t timeout_ms = 10 * 1000> +class TryAgainDecorator { + public: + template<class T, class... Args> + static Decorator<T(Args...)> DecorateFunction(T (*f)(Args ...)) { + RetryControl ctrl({0, interval_ms * 1000 * 1000}, timeout_ms); + return Decorator<T(Args...)> + (std::function<T(Args...)>(f), ctrl); + } +}; + +} // namespace base + +#endif //< BASE_TRY_AGAIN_DECORATOR_H_ -- 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 Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel