Thanks Hans and Anders for your good comments. The updated patch is just sent out. Please help to have a look. Thanks a lot!
Regards, Vu > -----Original Message----- > From: Hans Nordebäck [mailto:hans.nordeb...@ericsson.com] > Sent: Thursday, November 30, 2017 1:07 PM > To: Anders Widell <anders.wid...@ericsson.com>; Vu Minh Nguyen > <vu.m.ngu...@dektech.com.au> > Cc: opensaf-devel@lists.sourceforge.net > Subject: RE: [PATCH 1/1] base: create generic try-again handling decorator for > AIS APIs [#2702] > > agree, constexpr should be fine. /HansN > > -----Original Message----- > From: Anders Widell > Sent: den 30 november 2017 13:05 > To: Hans Nordebäck <hans.nordeb...@ericsson.com>; Vu Minh Nguyen > <vu.m.ngu...@dektech.com.au> > Cc: opensaf-devel@lists.sourceforge.net > Subject: Re: [PATCH 1/1] base: create generic try-again handling decorator for > AIS APIs [#2702] > > I have two comments: > > 1) I think this should be put under src/ais (but not src/ais/include) instead > of > putting it in src/base. > > 2) Could you think about if it is possible to make the retry time and interval > constexpr? > > regards, > > Anders Widell > > > On 11/30/2017 01:01 PM, Hans Nordebäck wrote: > > Hi Vu, > > > > please see some comments inlined below/Regards HansN > > > > > > On 11/28/2017 02:13 PM, Vu Minh Nguyen wrote: > >> 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; > > [HansN] use an unnamed namespace instead of static: > > namespace { > > unsigned counter = 0; > > } > > > >> + > >> +SaAisErrorT TestMethod() { > >> + ++counter; > >> + return SA_AIS_ERR_TRY_AGAIN; > >> +} > > [HansN] shouldn't this function be declared extern "C" ? > > > >> + > >> +TEST(TryAgainDecorator, DefaultRetryControl) { > >> + // default interval = 40ms, timeout = 10 * 1000ms > >> + using DefaultDecorator = base::TryAgainDecorator<>; > >> + auto DecorTestMethod = > >> DefaultDecorator::DecorateFunction(TestMethod); > >> + > >> + DecorTestMethod(); > > > > [HansN] the return code from the DecorTestMethod should be validated > >> + 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(); > > > > [HansN] the return code from the DecorTestMethod should be validated > >> + 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 { > >> + > > [HansN] perhaps we can use a strategy/policy like pattern instead? > > What do you say about something like the following: > > > > > > struct RetryStrategy { > > > > virtual int nTries() = 0; > > > > virtual int retryInterval() = 0; > > > > }; > > > > struct DefaultRetryStrategy : public RetryStrategy { > > > > int nTries() {return 10;} > > > > int retryInterval() {return 10;} > > > > }; > > > > struct AnotherRetryStrategy : public RetryStrategy { > > > > int nTries() {return 100;} > > > > int retryInterval() {return 100;} > > > > }; > > > > DefaultRetryStrategy DfltStrategy; > > > > AnotherRetryStrategy AnotherStrategy; > > > > int SA_AIS_ERR_TRY_AGAIN = 0; > > > > // > > > > template <typename> class Decorator; > > > > template <typename T, typename... Args> > > > > class Decorator<T(Args ...)> { > > > > public: > > > > explicit Decorator(std::function<T(Args...)> f, RetryStrategy > > &strategy) > > > > : f_(f), strategy_(strategy) {} > > > > T operator()(Args... args) { > > > > std::cout << "Call the decorated function" << std::endl; > > > > int rc = f_(args...); > > > > int n_tries = 1; > > > > while (rc == SA_AIS_ERR_TRY_AGAIN && > > > > n_tries < strategy_.nTries()) { > > > > base::Sleep(strategy_.retryInterval()); > > > > rc = f_(args...); > > > > n_tries++; > > > > } > > > > std::cout << "return code is " << rc << std::endl; > > > > std::cout << "add all common retry logic here, etc " << std::endl; > > > > return rc; > > > > } > > > > RetryStrategy &strategy_; > > > > std::function<T(Args ...)> f_; > > > > }; > > > > template<typename T, typename... Args> > > > > Decorator<T(Args...)> make_decorator(T (*f)(Args...), RetryStrategy > > &strategy=DfltStrategy) { > > > > return Decorator<T(Args...)>(std::function<T(Args...)>(f), > > strategy); > > > > } > > > > int main() { > > > > int rc = 0; > > > > auto saImmOmInitialize_d = make_decorator(saImmOmInitialize); > > > > std::cout << typeid(saImmOmInitialize_d).name() << std::endl; > > > > rc = saImmOmInitialize_d(4711); > > > > std::cout << "rc: " << rc << std::endl; > > > > auto saImmOmSelectionObjectGet_d = > > make_decorator(saImmOmSelectionObjectGet, AnotherStrategy); > > > > rc = saImmOmSelectionObjectGet_d(4712, "hello world!"); > > > > : > > > > > >> +//> > >> +// 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_ > > > ------------------------------------------------------------------------------ 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