Hi all, I have added static assertion for validating retry control parameters, so that user will get complier error if giving invalid inputs. Below is the diff.
diff --git a/src/base/try_again_decorator.h b/src/base/try_again_decorator.h index e676697..b11194d 100644 --- a/src/base/try_again_decorator.h +++ b/src/base/try_again_decorator.h @@ -98,6 +98,8 @@ class TryAgainDecorator { public: template<class T, class... Args> static Decorator<T(Args...)> DecorateFunction(T (*f)(Args ...)) { + static_assert((timeout_ms / interval_ms) > 1, + "timeout must be larger than interval!"); RetryControl ctrl({0, interval_ms * 1000 * 1000}, timeout_ms); return Decorator<T(Args...)> (std::function<T(Args...)>(f), ctrl); Regards, Vu > -----Original Message----- > From: Vu Minh Nguyen [mailto:vu.m.ngu...@dektech.com.au] > Sent: Tuesday, November 28, 2017 2:13 PM > To: anders.wid...@ericsson.com; hans.nordeb...@ericsson.com > Cc: opensaf-devel@lists.sourceforge.net; Vu Minh Nguyen > <vu.m.ngu...@dektech.com.au> > Subject: [PATCH 1/1] base: create generic try-again handling decorator for AIS > APIs [#2702] > > 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