1 /*
2  * Copyright (C) 2009-2014 Codership Oy <info@codership.com>
3  */
4 
5 /*!
6  * @file conf.hpp
7  *
8  * @brief Configuration parameters and utility templates.
9  */
10 
11 #ifndef GCOMM_CONF_HPP
12 #define GCOMM_CONF_HPP
13 
14 #include "gu_config.hpp"
15 #include "gu_uri.hpp"
16 #include "gu_throw.hpp"
17 
18 namespace gcomm
19 {
20     /*!
21      * Configuration parameter definitions.
22      *
23      * Transport definition and configuration parameters are passed to
24      * Transport::create() in the URI form. URI scheme part defines
25      * which transport is returned. Currently recognized are "tcp", "gmcast"
26      * and "pc". This will change in the future.
27      *
28      * URI format is the following:
29      * gcomm://[<peer_host>[:<peer_port>]][?<key1>=<val1>&<key2>=<val2>]...
30      * The key/value pairs can be used to pass configuration parameters to
31      * gcomm layers.
32      *
33      * Time periods as parameter values follow ISO8601 duration representation
34      * (as represented in http://en.wikipedia.org/wiki/ISO_8601#Durations).
35      * Examples:
36      *  - PT1S - one second
37      *  - PT1M30S = one minute 30 secs
38      *  - P1DT6H = one day, 6 hours
39      *
40      * To get subsecond resolution, second part can be represented as decimal
41      * number, but currently it is not recommended due to bug in Period
42      * parsing routine (rounding errors can result inaccurate boundary
43      * value checking).
44      */
45     struct Conf
46     {
47         static std::string const ProtonetBackend;
48         static std::string const ProtonetVersion;
49 
50         /*!
51          * @brief TCP non-blocking flag ("socket.non_blocking")
52          *
53          * Parameter value is boolean (passed 0 or 1) denoting whether
54          * the socket should or should not be in non-blocking state.
55          */
56         static std::string const TcpNonBlocking;
57 
58         /*!
59          * @brief Algorithm for message checksums:
60          * 0 - none    (backward compatible)
61          * 1 - CRC-32  (backward compatible)
62          * 2 - CRC-32C (optimized and potentially HW-accelerated on Intel CPUs)
63          */
64         static std::string const SocketChecksum;
65 
66         /*!
67          * @brief Socket receive buffer size in bytes
68          */
69         static std::string const SocketRecvBufSize;
70 
71         /*!
72          * @brief Socket send buffer size in bytes.
73          */
74         static std::string const SocketSendBufSize;
75 
76         /*!
77          * @brief GMCast scheme for transport URI ("gmcast")
78          */
79         static std::string const GMCastScheme;
80 
81         /*!
82          * @brief GMCast protocol version
83          */
84         static std::string const GMCastVersion;
85 
86         /*!
87          * @brief GMCast group name ("gmcast.group")
88          *
89          * String denoting group name. Max length of string is 16. Peer nodes
90          * accept GMCast connection only if the group names match.
91          */
92         static std::string const GMCastGroup;
93 
94         /*!
95          * @brief GMCast listening address ("gmcast.listen_addr")
96          *
97          * Listening address for GMCast. Address is currently passed in
98          * URI format (for example tcp://192.168.3.1:4567) and it should
99          * be passed as the last configuration parameter in order to
100          * avoid confusion. If parameter value is undefined, GMCast
101          * starts listening all interfaces at default port 4567.
102          */
103         static std::string const GMCastListenAddr;
104 
105         /*!
106          * @brief GMCast multicast address ("gmcast.mcast_addr")
107          *
108          * Multicast address for GMCast. By default multicast socket
109          * is bound to the same interface as conf::GMCastListenAddr.
110          * If multicast interface must be specified, the only way
111          * to do it is currently via listening address configuration.
112          */
113         static std::string const GMCastMCastAddr;
114 
115         /*!
116          * @brief GMCast multicast port ("gmcast.mcast_port")
117          *
118          * Multicast port for GMCast. By default multicast uses the
119          * same port as GMCast TCP connections.
120          */
121         static std::string const GMCastMCastPort;
122 
123         /*!
124          * @brief GMCast multicast TTL ("gmcast.mcast_ttl")
125          *
126          * This parameter controls multicast packet TTL. By default it
127          * is set to 1 and usually it should not be changed unless
128          * adviced so. This means that multicast is limited to single LAN
129          * segment.
130          */
131         static std::string const GMCastMCastTTL;
132 
133         static std::string const GMCastTimeWait;
134         static std::string const GMCastPeerTimeout;
135 
136         /*!
137          * @brief Maximum initial reconnect attempts
138          *
139          * Maximum initial reconnect attempts for address reported by peer.
140          */
141         static std::string const GMCastMaxInitialReconnectAttempts;
142 
143         /*!
144          * @brief Add or remove peer address.
145          *
146          * Setting value to add:<scheme>://<ip>:<port> will inject new peer
147          * address in address list. Setting value to del:<scheme>://<ip>:<port>
148          * will remove peer address from list (via forget procedure).
149          */
150         static std::string const GMCastPeerAddr;
151 
152         /*!
153          * @brief Isolate node from peers
154          *
155          * Setting this value to 'true' closes all conections
156          * and will prevent forming of new connections until
157          * value is set again to 'false'. This parameter should be
158          * used for testing purposes only and it will not be visible
159          * in global configuration array.
160          */
161         static std::string const GMCastIsolate;
162 
163         /*!
164          * @brief Segment identifier for segmentation.
165          */
166         static std::string const GMCastSegment;
167 
168 
169         /*!
170          * @brief EVS scheme for transport URI ("evs")
171          */
172         static std::string const EvsScheme;
173 
174         /*!
175          * @brief EVS protocol version
176          */
177         static std::string const EvsVersion;
178 
179         /*!
180          * @brief EVS view forget timeout ("evs.view_forget_timeout")
181          *
182          * This timeout controls how long information about
183          * known group views is maintained. This information is needed
184          * to filter out delayed messages from previous views that are not
185          * live anymore. Default value is 5 minutes and there is usually not
186          * need to change it.
187          */
188         static std::string const EvsViewForgetTimeout;
189 
190         /*!
191          * @brief EVS suspect timeout ("evs.suspect_timeout")
192          *
193          * This timeout controls how long node can remain silent until
194          * it is put under suspicion. If majority of the current group
195          * agree that the node is under suspicion, it is discarded from
196          * group and new group view is formed immediately. If majority
197          * of the group does not agree about suspicion, Conf::EvsInactiveTimeout
198          * is waited until forming of new group will be attempted.
199          * Default value is 5 seconds.
200          */
201         static std::string const EvsSuspectTimeout;
202 
203         /*!
204          * @brief EVS inactive timeout ("evs.inactive_timeout")
205          *
206          * This timeout control how long node can remain completely silent
207          * until it is discarded from the group. This is hard limit, unlike
208          * Conf::EvsSuspectTimeout, and the node is discarded even if it
209          * becomes live during the formation of the new group. Default value
210          * is 15 seconds.
211          */
212         static std::string const EvsInactiveTimeout;
213 
214         /*!
215          * @brief EVS inactive check period ("evs.inactive_check_period")
216          *
217          * This period controls how often node liveness is checked. Default
218          * is 1 second and there is no need to change this unless
219          * Conf::EvsSuspectTimeout or Conf::EvsInactiveTimeout is adjusted
220          * to smaller value. Default value is 1 second, minimum is 0.1 seconds
221          * and maximum is Conf::EvsSuspectTimeout/2.
222          */
223         static std::string const EvsInactiveCheckPeriod;
224 
225 
226         static std::string const EvsInstallTimeout;
227 
228         /*!
229          * @brief EVS keepalive period ("evs.keepalive_period")
230          *
231          * This timeout controls how often keepalive messages are
232          * sent into network. Node liveness is determined with
233          * these keepalives, so the value sould be significantly smaller
234          * than Conf::EvsSuspectTimeout. Default value is 1 second,
235          * minimum is 0.1 seconds and maximum is Conf::EvsSuspectTimeout/3.
236          */
237         static std::string const EvsKeepalivePeriod;
238 
239         /*!
240          * @brief EVS join retransmission period ("evs.join_retrans_period")
241          *
242          * This parameter controls how often join messages are retransmitted
243          * during group formation. There is usually no need to adjust
244          * this value. Default value is 0.3 seconds, minimum is 0.1 seconds
245          * and maximum is Conf::EvsSuspectTimeout/3.
246          */
247         static std::string const EvsJoinRetransPeriod;
248 
249         /*!
250          * @brief EVS statistics reporting period ("evs.stats_report_period")
251          *
252          * This parameters controls how often statistics information is
253          * printed in the log. This parameter has effect only if
254          * statistics reporting is enabled via Conf::EvsInfoLogMask. Default
255          * value is 1 minute.
256          */
257         static std::string const EvsStatsReportPeriod;
258 
259         /*!
260          * @brief EVS debug log mask ("evs.debug_log_mask")
261          *
262          * This mask controls what debug information is printed in the logs
263          * if debug logging is turned on. Mask value is bitwise-or
264          * from values gcomm::evs::Proto::DebugFlags. By default only
265          * state information is printed.
266          */
267         static std::string const EvsDebugLogMask;
268 
269         /*!
270          * @brief EVS info log mask ("evs.info_log_mask")
271          *
272          * This mask controls what info log is printed in the logs.
273          * Mask value is bitwise-or from values gcomm::evs::Proto::InfoFlags.
274          */
275         static std::string const EvsInfoLogMask;
276 
277         /*!
278          * @brief EVS send window ("evs.send_window")
279          *
280          * This parameter controls how many messages protocol layer is
281          * allowed to send without getting all acknowledgements for any of them.
282          * Default value is 32.
283          */
284         static std::string const EvsSendWindow;
285 
286         /*!
287          * @brief EVS user send window ("evs.user_send_window")
288          *
289          * Like Conf::EvsSendWindow, but for messages for which sending
290          * is initiated by call from upper layer. Default value is 16.
291          */
292         static std::string const EvsUserSendWindow;
293 
294         /*!
295          * @brief EVS message aggregation mode ("evs.use_aggregate")
296          *
297          * This parameter controls whether EVS is allowed to aggregate
298          * several user messages into one message. By default this option
299          * is enabled and there should be no need to disable it unless
300          * adviced so.
301          */
302         static std::string const EvsUseAggregate;
303 
304         /*!
305          * @brief Period to generate keepalives for causal messages
306          *
307          */
308         static std::string const EvsCausalKeepalivePeriod;
309 
310         /*!
311          * @brief EVS maximum install timeouts ("evs.max_install_timeouts")
312          *
313          * This parameter controls how many install attempts are done
314          * before declaring other nodes as inactive and trying to re-establish
315          * group via singleton views.
316          */
317         static std::string const EvsMaxInstallTimeouts;
318 
319         /*!
320          * @brief Margin over keepalive period after which node is declared
321          *        delayed. This should be greater than the largest RTT
322          *        between cluster nodes.
323          */
324         static std::string const EvsDelayMargin;
325 
326         /*!
327          * @brief Period which determines how long delayed node is kept in
328          *        delayed list after it becomes responsive again.
329          *
330          * The actual time that node stays in delayed list is
331          * EvsDelayedKeepPeriod times the number of changes between
332          * OK and DELAYED state.
333          */
334         static std::string const EvsDelayedKeepPeriod;
335 
336         /*!
337          * @brief List of nodes (UUIDs) that should be evicted permanently from
338          * cluster.
339          *
340          * Setting value to nil UUID will clear the evict list.
341          */
342         static std::string const EvsEvict;
343 
344         /*!
345          * @brief Autoevict threshold.
346          */
347         static std::string const EvsAutoEvict;
348 
349         /*!
350          * @brief PC scheme for transport URI ("pc")
351          */
352         static std::string const PcScheme;
353 
354         /*!
355          * @brief PC protocol version
356          */
357         static std::string const PcVersion;
358 
359         /*!
360          * @brief PC split-brain mode
361          *
362          * This parameter controls whether PC is allowed to continue
363          * operation despite of possible split brain condition.
364          */
365         static std::string const PcIgnoreSb;
366 
367         /*!
368          * @brief PC quorum mode
369          *
370          * This parameter controls whether PC is allowed to continue
371          * operation despite of quorum loss.
372          */
373         static std::string const PcIgnoreQuorum;
374 
375         /*!
376          * @brief PC message checksumming
377          *
378          * This parameter controls whether PC layer does message
379          * checksumming.
380          */
381         static std::string const PcChecksum;
382 
383         /*!
384          * @brief PC starup announce timeout
385          */
386         static std::string const PcAnnounceTimeout;
387 
388         /*!
389          * @brief PC close linger timeout
390          */
391         static std::string const PcLinger;
392 
393         /*!
394          * @brief PC newer prim view overrides
395          */
396         static std::string const PcNpvo;
397 
398         /*!
399          * @brief If set during runtime bootstraps new PC
400          */
401         static std::string const PcBootstrap;
402 
403         /*!
404          * @brief Wait for prim comp unconditionally if set to true
405          */
406         static std::string const PcWaitPrim;
407 
408         /*!
409          * @brief Timeout on waiting for primary component
410          */
411         static std::string const PcWaitPrimTimeout;
412 
413         /*!
414          * @brief Node weight in prim comp voting
415          */
416         static std::string const PcWeight;
417 
418         /*!
419          * @brief PC recovery from cluster crash
420          */
421         static std::string const PcRecovery;
422 
423         static void register_params(gu::Config&);
424 
425         static void check_params(const gu::Config&);
426 
427         struct Check
428         {
Checkgcomm::Conf::Check429             Check(gu::Config& conf) { check_params(conf); }
~Checkgcomm::Conf::Check430             virtual ~Check() {} // to pacify older GCCs with -Werror=effc++
431         };
432 
433         static size_t check_recv_buf_size(const std::string& val);
434         static size_t check_send_buf_size(const std::string& val);
435     };
436 
437 
438     // Helper templates to read configuration parameters.
439 
_conf_param(const gu::URI & uri,const std::string & param,const T * default_value=0,const T * min_value=0,const T * max_value=0)440     template <typename T> T _conf_param(const gu::URI& uri,
441                                         const std::string& param,
442                                         const T* default_value = 0,
443                                         const T* min_value = 0,
444                                         const T* max_value = 0)
445     {
446         T ret;
447         try
448         {
449             ret = gu::from_string<T>(uri.get_option(param));
450         }
451         catch (gu::NotFound& e)
452         {
453             // cppcheck-suppress nullPointer
454             if (default_value == 0)
455             {
456                 gu_throw_error(EINVAL)
457                     << "param " << param << " not found from uri "
458                     << uri.to_string();
459             }
460             // cppcheck-suppress nullPointer
461             ret = *default_value;
462         }
463 
464         if (min_value != 0 && *min_value > ret)
465         {
466             gu_throw_error(EINVAL)
467                 << "param " << param << " value " << ret << " out of range "
468                 << "min allowed " << *min_value;
469         }
470 
471         if (max_value != 0 && *max_value < ret)
472         {
473             gu_throw_error(EINVAL)
474                 << "param " << param << " value " << ret << " out of range "
475                 << "max allowed " << *max_value;
476         }
477         return ret;
478     }
479 
conf_param(const gu::URI & uri,const std::string & param)480     template <typename T> T conf_param(const gu::URI& uri,
481                                        const std::string& param)
482     {
483         return _conf_param<T>(uri, param, 0, 0, 0);
484     }
485 
conf_param_def(const gu::URI & uri,const std::string & param,const T & default_value)486     template <typename T> T conf_param_def(const gu::URI& uri,
487                                            const std::string& param,
488                                            const T& default_value)
489     {
490         return _conf_param(uri, param, &default_value);
491     }
492 
conf_param_range(const gu::URI & uri,const std::string & param,const T & min_value,const T & max_value)493     template <typename T> T conf_param_range(const gu::URI& uri,
494                                              const std::string& param,
495                                              const T& min_value,
496                                              const T& max_value)
497     {
498         return _conf_param(uri, param, 0, &min_value, &max_value);
499     }
500 
conf_param_def_min(const gu::URI & uri,const std::string & param,const T & default_value,const T & min_value)501     template <typename T> T conf_param_def_min(const gu::URI& uri,
502                                                const std::string& param,
503                                                const T& default_value,
504                                                const T& min_value)
505 
506     {
507         return _conf_param(uri, param, &default_value, &min_value);
508     }
509 
conf_param_def_max(const gu::URI & uri,const std::string & param,const T & default_value,const T & max_value)510     template <typename T> T conf_param_def_max(const gu::URI& uri,
511                                                const std::string& param,
512                                                const T& default_value,
513                                                const T& max_value)
514 
515     {
516         return _conf_param(uri, param, &default_value,
517                            reinterpret_cast<const T*>(0), &max_value);
518     }
519 
conf_param_def_range(const gu::URI & uri,const std::string & param,const T & default_value,const T & min_value,const T & max_value)520     template <typename T> T conf_param_def_range(const gu::URI& uri,
521                                                  const std::string& param,
522                                                  const T& default_value,
523                                                  const T& min_value,
524                                                  const T& max_value)
525     {
526         return _conf_param(uri, param, &default_value, &min_value, &max_value);
527     }
528 
529 
530 
531     template <typename T>
param(gu::Config & conf,const gu::URI & uri,const std::string & key,const std::string & def,std::ios_base & (* f)(std::ios_base &)=std::dec)532     T param(gu::Config&        conf,
533             const gu::URI&     uri,
534             const std::string& key,
535             const std::string& def,
536             std::ios_base& (*f)(std::ios_base&) = std::dec)
537     {
538         T ret;
539 
540         try
541         {
542             std::string cnf(conf.get(key, def));
543             std::string val(uri.get_option(key, cnf));
544             try
545             {
546                 ret = gu::from_string<T>(val, f);
547             }
548             catch (gu::NotFound)
549             {
550                 gu_throw_error(EINVAL) << "Bad value '" << val
551                                        << "' for parameter '" << key << "'";
552             }
553         }
554         catch (gu::NotFound)
555         {
556             gu_throw_error(EINVAL) << "Unrecognized parameter '" << key << "'";
557         }
558 
559         return ret;
560     }
561 
562     template <typename T>
check_range(const std::string & key,const T & val,const T & min,const T & max)563     T check_range(const std::string& key,
564                   const T&           val,
565                   const T&           min,
566                   const T&           max)
567     {
568         if (val < min || val >= max)
569         {
570             gu_throw_error(ERANGE) << "parameter '" << key << "' value " << val
571                                    << " is out of range [" << min
572                                    << "," << max << ")";
573         }
574         return val;
575     }
576 
577     template <typename T>
check_range(const std::string & key,const std::string & val,const T & min,const T & max)578     T check_range(const std::string& key,
579                   const std::string& val,
580                   const T&           min,
581                   const T&           max)
582     {
583         return check_range<T>(key, gu::Config::from_config<T>(val), min, max);
584     }
585 
586     template <typename T>
check_range(const gu::Config & conf,const std::string & key,const T & min,const T & max)587     T check_range(const gu::Config&  conf,
588                   const std::string& key,
589                   const T&           min,
590                   const T&           max)
591     {
592         return check_range<T>(key, conf.get(key), min, max);
593     }
594 
595 } // namespace gcomm
596 
597 #endif // GCOMM_CONF_HPP
598