Changes of Revision 17
[-] | Changed | glb.changes |
1
2 ------------------------------------------------------------------- 3 +Tue Feb 12 19:53:19 UTC 2013 - cs@linux-administrator.com 4 + 5 +- update to release 0.9.2 6 + 7 +------------------------------------------------------------------- 8 Mon Jan 14 20:43:53 UTC 2013 - cs@linux-administrator.com 9 10 - update to release 0.9.1 11 |
||
[-] | Changed | glb.spec ^ |
8 1
2 Name: glb 3 -Version: 0.9.1 4 +Version: 0.9.2 5 Release: 1 6 License: GPLv2 7 Group: Applications/System 8 |
||
[+] | Changed | glb-0.9.2.tar.bz2/ChangeLog ^ |
@@ -1,3 +1,12 @@ +2013-01-18 alex +- New option -T|--top: all policies use only top-weighted destinations for + routing. E.g. in the presence of destinations with weights 1 and 2 only + the latter will be used to route connections to until all of them fail. +- New policy 'single': all connections are directed to only one destination + chosen by highest weight. +- Added SO_KEEPALIVE option to server side sockets to avoid stalled connections + Version 0.9.2 + 2013-01-10 alex - Added asynchronous connection processing by default. -Y option to turn back old synchronous (one-at-a-time) bevaviour. | ||
[+] | Changed | glb-0.9.2.tar.bz2/README ^ |
@@ -38,19 +38,28 @@ BALANCING POLICIES: =================== -GLB supports four balancing "policies": +GLB supports five balancing "policies": -a) "least connected" - new connection will be directed to the server with least - connections (corrected for server "weight"). This is the default policy. +a) "least connected" - new connection will be directed to the server with + least connections (corrected for server "weight"). This policy is default. b) "round-robin" - each new connection is routed to the next destination - in the list in circular order. This policy does not use node weights. + in the list in circular order. -c) "random" - connections are distributed randomly between the servers. +c) "single" - all connections are routed to a single server with the highest + weight available. All routing will stick to that server until it fails or + a server with a strictly higher weight is introduced. -d) "source tracking" - connections originating from the same address are +d) "random" - connections are distributed randomly between the servers. + +e) "source tracking" - connections originating from the same address are directed to the same server. For details about this policy see below. +-T|--top option was introduced in GLB 0.9.2. It restricts all balancing +policies to a subset of destinations with top weight. E.g. if there are servers +configured with weight 1 and 2, all balancing will happen only between servers +with weight 2 as long as at least one of them is avaialble. + MAXIMUM CONCURRENT CONNECTIONS: =============================== @@ -197,16 +206,16 @@ Server version: 5.5.28 Source distribution, wsrep_24dev.7.r3830 ... -Here GLB_VIP=3306 is interpreted as 127.0.0.1:3306, and GLB_TARGETS as +Here GLB_BIND=3306 is interpreted as 127.0.0.1:3306, and GLB_TARGETS as 192.168.0.1:3306,192.168.0.2:3306,192.168.0.3:3306 (note port in GLB_BIND). Note that mysql is connecting to 127.0.0.1:3306 as well and since this -address matches GLB_BIND, connection is intecepted and directed to the real -server. +address matches GLB_BIND, connection is intecepted and directed to the server +from the GLB_TARGETS list. Additional libglb parameters: GLB_POLICY=random|source - Default libglb balancing policy is "round-robin", "random" and + Default libglb balancing policy is "round-robin", "single", "random" and "source tracking" policies can be specified with GLB_POLICY variable. (The meaning of GLB_POLICY=source in this case is that all connections from | ||
[+] | Changed | glb-0.9.2.tar.bz2/configure ^ |
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for glb 0.9.1. +# Generated by GNU Autoconf 2.69 for glb 0.9.2. # # Report bugs to <info@codership.com>. # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='glb' PACKAGE_TARNAME='glb' -PACKAGE_VERSION='0.9.1' -PACKAGE_STRING='glb 0.9.1' +PACKAGE_VERSION='0.9.2' +PACKAGE_STRING='glb 0.9.2' PACKAGE_BUGREPORT='info@codership.com' PACKAGE_URL='' @@ -1332,7 +1332,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures glb 0.9.1 to adapt to many kinds of systems. +\`configure' configures glb 0.9.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1403,7 +1403,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of glb 0.9.1:";; + short | recursive ) echo "Configuration of glb 0.9.2:";; esac cat <<\_ACEOF @@ -1513,7 +1513,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -glb configure 0.9.1 +glb configure 0.9.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2057,7 +2057,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by glb $as_me 0.9.1, which was +It was created by glb $as_me 0.9.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2987,7 +2987,7 @@ # Define the identity of the package. PACKAGE='glb' - VERSION='0.9.1' + VERSION='0.9.2' cat >>confdefs.h <<_ACEOF @@ -16676,7 +16676,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by glb $as_me 0.9.1, which was +This file was extended by glb $as_me 0.9.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -16742,7 +16742,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -glb config.status 0.9.1 +glb config.status 0.9.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" | ||
[+] | Changed | glb-0.9.2.tar.bz2/configure.ac ^ |
@@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(glb, 0.9.1, info@codership.com) +AC_INIT(glb, 0.9.2, info@codership.com) AC_CONFIG_SRCDIR([src/glb_main.c]) AC_CONFIG_HEADER([config.h]) AC_CANONICAL_SYSTEM | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_cmd.c ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2013 Codership Oy <info@codership.com> * - * $Id: glb_cmd.c 126 2013-01-08 03:36:55Z alex $ + * $Id: glb_cmd.c 138 2013-01-18 12:07:31Z alex $ */ #include "glb_cmd.h" @@ -20,6 +20,9 @@ typedef enum cmd_opt { + CMD_OPT_KEEPALIVE = 'K', + CMD_OPT_SINGLE = 'S', + CMD_OPT_TOP = 'T', CMD_OPT_VERSION = 'V', CMD_OPT_SYNCHRONOUS = 'Y', CMD_OPT_DEFER_ACCEPT = 'a', @@ -38,6 +41,9 @@ static option_t cmd_options[] = { + { "keepalive", NA, NULL, CMD_OPT_KEEPALIVE }, + { "single", NA, NULL, CMD_OPT_SINGLE }, + { "top", NA, NULL, CMD_OPT_TOP }, { "version", NA, NULL, CMD_OPT_VERSION }, { "defer-accept", NA, NULL, CMD_OPT_DEFER_ACCEPT }, { "round", NA, NULL, CMD_OPT_ROUND_ROBIN }, @@ -59,86 +65,29 @@ { 0, 0, 0, 0 } }; -void -glb_cmd_help (FILE* out, const char* progname) -{ - fprintf (out, - "Usage:\n %s [OPTIONS] LISTEN_ADDRESS " - "[DESTINATION_LIST]\nOPTIONS:\n", progname); - fprintf (out, - " -h|--help this help message.\n"); - fprintf (out, - " -a|--defer-accept " - "enable TCP_DEFER_ACCEPT on the listening socket\n" - " (default: disabled).\n"); - fprintf (out, - " -b|--round " - "round-robin destination selection policy.\n"); - fprintf (out, - " -c|--control [HOST:]PORT " - "listen for control requests on this address.\n"); - fprintf (out, - " -d|--daemon run as a daemon.\n"); - fprintf (out, - " -f|--fifo <fifo name> name of the FIFO file for control.\n"); - fprintf (out, - " -m|--max_conn N " - "maximum allowed number of client connections (OS dependent).\n"); - fprintf (out, - " -n|--nodelay " - "*DISABLE* TCP_NODELAY socket option\n" - " (default: enabled).\n"); - fprintf (out, - " -r|--random " - "route connections to randomly selected destination.\n"); - fprintf (out, - " -s|--source " - "turn on source tracking: route connections from one\n" - " source to the same destination.\n"); - fprintf (out, - " -t|--threads N " - "number of working threads (connection pools).\n"); - fprintf (out, - " -v|--verbose turn on verbose reporting.\n"); - fprintf (out, - " -Y " - "connect synchronously (one-at-a-time).\n"); - fprintf (out, - " -V|--version print program version.\n"); - fprintf (out, "LISTEN_ADDRESS:\n" - " [IP:]PORT " - "where to listen for incoming TCP connections at.\n" - " " - "(without IP part - bind to all interfaces)\n" - ); - fprintf (out, "DESTINATION_LIST:\n" - " [H1[:P1[:W1]]] [H2[:P2[:W2]]]... " - " - a space-separated list of destinations\n" - " in the form address:port:weight.\n"); - exit (EXIT_FAILURE); -} - // Defaults relevant to CLI static const char cmd_inc_addr_default[] = "0.0.0.0"; static const char cmd_ctrl_addr_default[] = "127.0.0.1"; -glb_cnf_t* -glb_cmd_parse (int argc, char* argv[]) +static void +cmd_parse_options (int argc, char* argv[], glb_cnf_t* tmp) { - glb_cnf_t* tmp = glb_cnf_init(); // initialize to defaults - const char** dst_list = NULL; - int opt = 0; - int opt_idx = 0; - char* endptr; - uint16_t inc_port; + int opt = 0; + int opt_idx = 0; + char* endptr; - if (!tmp) exit (EXIT_FAILURE); - - // parse options - while ((opt = getopt_long (argc, argv, "VYabc:dfhm:nt:rsv", cmd_options, + while ((opt = getopt_long (argc, argv, "KSTVYabc:dfhm:nt:rsv", cmd_options, &opt_idx)) != -1) { switch (opt) { + case CMD_OPT_KEEPALIVE: + tmp->keepalive = false; + break; + case CMD_OPT_SINGLE: + tmp->policy = GLB_POLICY_SINGLE; // implies CMD_OPT_TOP + case CMD_OPT_TOP: + tmp->top = true; + break; case CMD_OPT_VERSION: glb_print_version (stdout); if (argc == 2) exit(0); @@ -201,6 +150,91 @@ cmd_options[opt_idx].name, opt); } } +} + +void +glb_cmd_help (FILE* out, const char* progname) +{ + fprintf (out, + "Usage:\n %s [OPTIONS] LISTEN_ADDRESS " + "[DESTINATION_LIST]\nOPTIONS:\n", progname); + fprintf (out, + " -h|--help this help message.\n"); + fprintf (out, + " -a|--defer-accept " + "enable TCP_DEFER_ACCEPT on the listening socket\n" + " (default: disabled).\n"); + fprintf (out, + " -b|--round " + "round-robin destination selection policy.\n"); + fprintf (out, + " -c|--control [HOST:]PORT " + "listen for control requests on this address.\n"); + fprintf (out, + " -d|--daemon run as a daemon.\n"); + fprintf (out, + " -f|--fifo <fifo name> name of the FIFO file for control.\n"); + fprintf (out, + " -m|--max_conn N " + "maximum allowed number of client connections (OS dependent).\n"); + fprintf (out, + " -n|--nodelay " + "*DISABLE* TCP_NODELAY socket option\n" + " (default: enabled).\n"); + fprintf (out, + " -r|--random " + "route connections to randomly selected destination.\n"); + fprintf (out, + " -s|--source " + "turn on source tracking: route connections from one\n" + " source to the same destination.\n"); + fprintf (out, + " -t|--threads N " + "number of working threads (connection pools).\n"); + fprintf (out, + " -v|--verbose turn on verbose reporting.\n"); + fprintf (out, + " -K|--keepalive " + "*DISABLE* SO_KEEPALIVE socket option on server-side\n" + " sockets (default: enabled).\n"); + fprintf (out, + " -S|--single " + "direct all connections to a single destination\n" + " " + "with top weight.\n"); + fprintf (out, + " -T|--top " + "only balance between destinations with top weight.\n"); + fprintf (out, + " -V|--version print program version.\n"); + fprintf (out, + " -Y " + "connect synchronously (one-at-a-time).\n"); + fprintf (out, "LISTEN_ADDRESS:\n" + " [IP:]PORT " + "where to listen for incoming TCP connections at.\n" + " " + "(without IP part - bind to all interfaces)\n" + ); + fprintf (out, "DESTINATION_LIST:\n" + " [H1[:P1[:W1]]] [H2[:P2[:W2]]]... " + " - a space-separated list of destinations\n" + " in the form address:port:weight.\n"); + exit (EXIT_FAILURE); +} + + +glb_cnf_t* +glb_cmd_parse (int argc, char* argv[]) +{ + glb_cnf_t* tmp = glb_cnf_init(); // initialize to defaults + const char** dst_list = NULL; + uint16_t inc_port; + + if (!tmp) exit (EXIT_FAILURE); + + // parse options + cmd_parse_options (argc, argv, tmp); // first non-option argument if (optind >= argc) { | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_cnf.c ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2012-2013 Codership Oy <info@codership.com> * - * $Id: glb_cnf.c 126 2013-01-08 03:36:55Z alex $ + * $Id: glb_cnf.c 138 2013-01-18 12:07:31Z alex $ */ #include "../config.h" // for version @@ -30,6 +30,7 @@ ret->n_threads = 1; ret->max_conn = glb_get_conn_limit(); ret->nodelay = true; + ret->keepalive = true; ret->policy = GLB_POLICY_LEAST; #else ret->policy = GLB_POLICY_ROUND; @@ -145,7 +146,7 @@ static const char* policy_str[GLB_POLICY_MAX] = { - "least connected", "round-robin", "random", "source" + "least connected", "round-robin", "single", "random", "source" }; void @@ -160,12 +161,15 @@ fprintf (out, "Control address: %s\n", cnf->ctrl_set ? glb_socket_addr_to_string (&cnf->ctrl_addr) : "none"); - fprintf (out, "Number of threads: %d, max conn: %d, policy: '%s', " - "nodelay: %s, defer accept: %s, verbose: %s, daemon: %s\n", + fprintf (out, "Number of threads: %d, max conn: %d, policy: '%s', top: %s, " + "nodelay: %s, keepalive: %s, defer accept: %s, verbose: %s, " + "daemon: %s\n", cnf->n_threads, cnf->max_conn, policy_str[cnf->policy], + cnf->top ? "YES" : "NO", cnf->nodelay ? "ON" : "OFF", + cnf->keepalive ? "ON" : "OFF", cnf->defer_accept ? "ON" : "OFF", cnf->verbose ? "ON" : "OFF", cnf->daemonize ? "YES" : "NO"); | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_cnf.h ^ |
@@ -1,7 +1,7 @@ /* - * Copyright (C) 2012 Codership Oy <info@codership.com> + * Copyright (C) 2012-2013 Codership Oy <info@codership.com> * - * $Id: glb_cnf.h 126 2013-01-08 03:36:55Z alex $ + * $Id: glb_cnf.h 138 2013-01-18 12:07:31Z alex $ */ #ifndef _glb_cnf_h_ @@ -16,8 +16,9 @@ { GLB_POLICY_LEAST = 0, /* least connected */ GLB_POLICY_ROUND, /* round-robin */ + GLB_POLICY_SINGLE, /* single dest. with the top weight */ GLB_POLICY_RANDOM, /* random choice */ - GLB_POLICY_SOURCE /* same for one source */ + GLB_POLICY_SOURCE /* same dest. for same source */ } glb_policy_t; #define GLB_POLICY_MAX (GLB_POLICY_SOURCE + 1) @@ -31,11 +32,13 @@ int n_threads; // number of routing threads (1 .. oo) int max_conn; // max allowed client connections bool nodelay; // use TCP_NODELAY? + bool keepalive; // use SO_KEEPALIVE? bool defer_accept; // use TCP_DEFER_ACCEPT? bool verbose; // be verbose? bool daemonize; // become a daemon? bool synchronous; // connect synchronously #endif /* GLBD */ + bool top; // only use top weighted destinations bool ctrl_set; // was set? (false) glb_policy_t policy; // algorithm to use for load-balancing size_t n_dst; // number of destinations | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_env.c ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2012 Codership Oy <info@codership.com> * - * $Id: glb_env.c 98 2012-12-08 19:47:15Z alex $ + * $Id: glb_env.c 138 2013-01-18 12:07:31Z alex $ */ #include "glb_env.h" @@ -16,6 +16,7 @@ #include <assert.h> /* Environment variable names */ +static const char env_options[] = "GLB_OPTIONS"; // options string, same as cmd static const char env_bind[] = "GLB_BIND"; // address that should be balanced static const char env_policy[] = "GLB_POLICY"; static const char env_ctrl[] = "GLB_CONTROL"; // address to accept control @@ -26,20 +27,25 @@ static const char env_ctrl_addr_default[] = "127.0.0.1"; static const char env_bind_addr_default[] = "127.0.0.1"; -/* convert string into array of tokens */ +/*! + * convert string into array of tokens + * + * @param sep - additional separator to whitespace + */ static bool -env_parse_target_string (char* targets, - const char*** dst_list, - int* dst_num) +env_parse_token_string (char* tok_str, + const char*** tok_list, + int* tok_num, + int sep) { - assert (targets); + assert (tok_str); - *dst_list = NULL; - *dst_num = 0; + *tok_list = NULL; + *tok_num = 0; - if (!targets) return true; + if (!tok_str) return true; - size_t const tlen = strlen(targets); + size_t const tlen = strlen(tok_str); if (!tlen) return true; const char** list = NULL; @@ -48,38 +54,72 @@ size_t i; for (i = 1; i <= tlen; i++) /* we can skip the first string char */ { - if (isspace(targets[i]) || ',' == targets[i]) targets[i] = '\0'; - if (targets[i] == '\0' && targets[i-1] != '\0') num++;/* end of token */ + if (isspace(tok_str[i]) || sep == tok_str[i]) tok_str[i] = '\0'; + if (tok_str[i] == '\0' && tok_str[i-1] != '\0') num++;/* end of token */ } list = calloc (num, sizeof(const char*)); if (!list) return true; - list[0] = targets; + list[0] = tok_str; num = 1; for (i = 1; i <= tlen; i++) { - if (targets[i-1] == '\0' && targets[i] != '\0') /* beginning of token */ + if (tok_str[i-1] == '\0' && tok_str[i] != '\0') /* beginning of token */ { - list[num] = &targets[i]; + list[num] = &tok_str[i]; num++; } } - *dst_list = list; - *dst_num = num; + *tok_list = list; + *tok_num = num; return false; } +static inline bool +env_option_is (const char* opt, const char* shopt, const char* lopt) +{ + return false; //stub until 1.0 +} + +static void +env_parse_options (glb_cnf_t* cnf, char* o) +{ + if (!o) return; + + int argc = 0; + char** argv = NULL; + + if (env_parse_token_string (o, (const char***)&argv, &argc, '\0')) + return; + + int i; + for (i = 0; i < argc; i++) + { + // stub + } + + free (argv); +} + static void env_parse_policy (glb_cnf_t* cnf, const char* p) { cnf->policy = GLB_POLICY_ROUND; // default - if (p && !strcmp(p, "random")) cnf->policy = GLB_POLICY_RANDOM; - if (p && !strcmp(p, "source")) cnf->policy = GLB_POLICY_SOURCE; + if (p) + { + if (!strcmp(p, "single")) + { + cnf->policy = GLB_POLICY_SINGLE; + cnf->top = true; + } + else if (p && !strcmp(p, "random")) cnf->policy = GLB_POLICY_RANDOM; + else if (p && !strcmp(p, "source")) cnf->policy = GLB_POLICY_SOURCE; + } } static void @@ -105,14 +145,15 @@ glb_cnf_t* ret = glb_cnf_init(); // initialize to defaults if (!ret) return NULL; - err = glb_parse_addr(&ret->inc_addr, getenv(env_bind), env_bind_addr_default); + err = glb_parse_addr (&ret->inc_addr, getenv (env_bind), + env_bind_addr_default); if (err) goto failure; const char** dst_list = NULL; int dst_num = 0; uint16_t bind_port = glb_socket_addr_get_port (&ret->inc_addr); - if (!env_parse_target_string (getenv (env_targets), &dst_list, &dst_num)) + if (!env_parse_token_string (getenv(env_targets), &dst_list, &dst_num, ',')) { assert(dst_list); assert(dst_num >= 0); @@ -123,6 +164,7 @@ { ret = tmp; + env_parse_options (ret, getenv (env_options)); env_parse_policy (ret, getenv (env_policy)); env_parse_control (ret, getenv (env_ctrl)); } | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_pool.c ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2013 Codership Oy <info@codership.com> * - * $Id: glb_pool.c 132 2013-01-10 15:10:04Z alex $ + * $Id: glb_pool.c 141 2013-01-19 19:13:32Z alex $ */ #include "glb_misc.h" @@ -334,8 +334,12 @@ pool_handle_async_conn (pool_t* pool, pool_conn_end_t* dst_end) { + uint32_t const ka_opt = pool->cnf->keepalive * GLB_SOCK_KEEPALIVE; + dst_end->sock = glb_socket_create(&pool->addr_out, - GLB_SOCK_NODELAY | GLB_SOCK_NONBLOCK); + GLB_SOCK_NODELAY | + GLB_SOCK_NONBLOCK | + ka_opt); int error; if (dst_end->sock > 0) { int ret = connect (dst_end->sock, (struct sockaddr*)&dst_end->addr, @@ -1100,12 +1104,14 @@ ); if (len == buf_len) { buf[len - 1] = '\0'; + GLB_MUTEX_UNLOCK (&pool->lock); return (len - 1); } #else len += snprintf (buf + len, buf_len - len," %5d",pool->pool[i].n_conns); if (len == buf_len) { buf[len - 1] = '\0'; + GLB_MUTEX_UNLOCK (&pool->lock); return (len - 1); } #endif | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_router.c ^ |
@@ -4,7 +4,7 @@ * NOTE: connection count and usage make sense only for standalone balancer * so all operations on them are #ifdef GLBD ... #endif * - * $Id: glb_router.c 134 2013-01-11 15:43:49Z alex $ + * $Id: glb_router.c 142 2013-01-20 12:36:55Z alex $ */ #define _GNU_SOURCE 1 /* for function overloading */ @@ -22,6 +22,9 @@ #include <unistd.h> // for close() #include <time.h> #include <sys/time.h> +#include <float.h> // for DBL_EPSILON + +static double const GLB_DBL_EPSILON = DBL_EPSILON; #ifdef GLBD # include <stdio.h> @@ -59,7 +62,9 @@ unsigned int seed; // seed for rng int rrb_next; // round-robin cursor int n_dst; - time_t map_failed; + time_t map_failed; // last time the map was redone after failed dst + time_t top_failed; // last time top dst was redone after failed dst + router_dst_t* top_dst; router_dst_t* dst; }; @@ -69,21 +74,61 @@ static const double DST_RETRY_INTERVAL = 2.0; static inline bool -router_dst_is_good (const router_dst_t* const d, time_t const now) +router_dst_is_good (const router_dst_t* const d, + double const min_weight, + time_t const now) { - return (d->dst.weight > 0.0 && + return (d->dst.weight >= min_weight && difftime (now, d->failed) > DST_RETRY_INTERVAL); } static inline bool +router_top_dst_is_good (const router_dst_t* const d, time_t const now) +{ + return (d && router_dst_is_good (d, GLB_DBL_EPSILON, now)); +} + +static inline double +router_min_weight (const glb_router_t* const router, time_t const now) +{ + return (router_top_dst_is_good (router->top_dst, now) ? + router->top_dst->dst.weight : GLB_DBL_EPSILON); +} + +static inline bool router_uses_map (const glb_router_t* const router) { return (router->cnf->policy >= GLB_POLICY_RANDOM); } static void +router_redo_top (glb_router_t* router, time_t now) +{ + int i; + static double const factor = 1.0 + GLB_DBL_EPSILON; + double top_weight = router_min_weight (router, now) * factor; + + /* If router->top_dst is not failed, it will be changed only if there is a + * a non-failed dst with weight strictly higher than that of top_dst. + * If router->top_dst is failed, then it will be changed only if there is + * a non-failed dst with weight > 0. */ + + for (i = 0; i < router->n_dst; i++) + { + router_dst_t* d = &router->dst[i]; + + if (router_dst_is_good (d, top_weight, now)) + { + top_weight = d->dst.weight * factor; + router->top_dst = d; + } + } +} + +static void router_redo_map (glb_router_t* router, time_t now) { + double min_weight = router_min_weight(router, now); int i; // pass 1: calculate total weight of available destinations @@ -92,7 +137,7 @@ { router_dst_t* d = &router->dst[i]; - if (router_dst_is_good (d, now)) + if (router_dst_is_good (d, min_weight, now)) { total += d->dst.weight; d->map = d->dst.weight; @@ -172,6 +217,7 @@ } else { router->dst = tmp; + router->top_dst = NULL; d = router->dst + router->n_dst; router->n_dst++; d->dst = *dst; @@ -186,6 +232,7 @@ assert (d); assert (i >= 0 && i < router->n_dst); + router->top_dst = NULL; #ifdef GLBD router->conns -= d->conns; assert (router->conns >= 0); #endif @@ -220,7 +267,9 @@ #endif } - if (router_uses_map(router)) router_redo_map (router, time (NULL)); + time_t const now = time (NULL); + if (router->cnf->top) router_redo_top (router, now); + if (router_uses_map(router)) router_redo_map (router, now); assert (router->n_dst >= 0); assert (0 == router->busy_count); @@ -304,20 +353,20 @@ #ifdef GLBD // find a ready destination with minimal usage static router_dst_t* -router_choose_dst_least (glb_router_t* router) +router_choose_dst_least (glb_router_t* const router, time_t const now) { + double min_weight = router_min_weight (router, now); router_dst_t* ret = NULL; if (router->n_dst > 0) { double max_usage = 0.0; int i; - time_t now = time(NULL); for (i = 0; i < router->n_dst; i++) { router_dst_t* d = &router->dst[i]; if (d->usage > max_usage && - difftime (now, d->failed) > DST_RETRY_INTERVAL) { + router_dst_is_good (d, min_weight, now)) { ret = d; max_usage = d->usage; } @@ -330,9 +379,9 @@ // find next suitable destination by round robin static router_dst_t* -router_choose_dst_round (glb_router_t* router) +router_choose_dst_round (glb_router_t* const router, time_t const now) { - time_t now = time(NULL); + double min_weight = router_min_weight (router, now); int offset; for (offset = 0; offset < router->n_dst; offset++) @@ -341,7 +390,7 @@ router->rrb_next = (router->rrb_next + 1) % router->n_dst; - if (router_dst_is_good (d, now)) return d; + if (router_dst_is_good (d, min_weight, now)) return d; } return NULL; @@ -349,12 +398,12 @@ // find a ready destination by client source hint static router_dst_t* -router_choose_dst_hint (glb_router_t* router, uint32_t hint) +router_choose_dst_hint (glb_router_t* const router, + uint32_t const hint, + time_t const now) { if (router->n_dst <= 0) return NULL; - time_t now = time(NULL); - #if OLD // old way /* First we attempt target predefined by hint (hint % router->n_dst). * If that fails, we iterate over the rest. But for every client @@ -401,6 +450,13 @@ return NULL; } +static inline router_dst_t* +router_choose_dst_single (glb_router_t* const router, time_t const now) +{ + return (router_top_dst_is_good (router->top_dst, now) ? + router->top_dst : NULL); +} + static inline uint32_t router_random_hint (glb_router_t* router) { @@ -415,15 +471,24 @@ #define glb_connect connect static inline router_dst_t* -router_choose_dst (glb_router_t* router, uint32_t hint) +router_choose_dst (glb_router_t* const router, uint32_t hint) { + time_t const now = time(NULL); router_dst_t* ret = NULL; + if (router->cnf->top && router->top_failed != 0 && + difftime (now, router->top_failed) > DST_RETRY_INTERVAL) + { + router_redo_top (router, now); + router->top_failed = 0; + } + switch (router->cnf->policy) { - case GLB_POLICY_LEAST: ret = router_choose_dst_least (router); break; - case GLB_POLICY_ROUND: ret = router_choose_dst_round (router); break; + case GLB_POLICY_LEAST: ret = router_choose_dst_least (router, now); break; + case GLB_POLICY_ROUND: ret = router_choose_dst_round (router, now); break; + case GLB_POLICY_SINGLE: ret = router_choose_dst_single(router, now); break; case GLB_POLICY_RANDOM: hint = router_random_hint (router); - case GLB_POLICY_SOURCE: ret = router_choose_dst_hint (router, hint); + case GLB_POLICY_SOURCE: ret = router_choose_dst_hint (router, hint, now); } if (GLB_LIKELY(ret != NULL)) { @@ -465,11 +530,21 @@ static inline router_dst_t* router_choose_dst (glb_router_t* router, uint32_t hint) { + time_t const now = time(NULL); + + if (router->cnf->top && router->top_failed != 0 && + difftime (now, router->top_failed) > DST_RETRY_INTERVAL) + { + router_redo_top (router, now); + router->top_failed = 0; + } + switch (router->cnf->policy) { case GLB_POLICY_LEAST: return NULL; - case GLB_POLICY_ROUND: return router_choose_dst_round (router); + case GLB_POLICY_ROUND: return router_choose_dst_round (router, now); + case GLB_POLICY_SINGLE: return router_choose_dst_single (router, now); case GLB_POLICY_RANDOM: hint = router_random_hint (router); - case GLB_POLICY_SOURCE: return router_choose_dst_hint (router, hint); + case GLB_POLICY_SOURCE: return router_choose_dst_hint (router, hint, now); } return NULL; } @@ -477,13 +552,25 @@ #endif /* GLBD */ static inline void -router_dst_failed (glb_router_t* router, router_dst_t* dst) +router_dst_failed (glb_router_t* const router, router_dst_t* const dst) { - time_t now = time(NULL); - if (router_uses_map (router) && router_dst_is_good (dst, now)) + time_t const now = time(NULL); + double const min_weight = router_min_weight (router, now); + bool const dst_was_good = router_dst_is_good (dst, min_weight, now); + + dst->failed = now; + + if (dst == router->top_dst) + { + router_redo_top (router, now); + router->top_failed = now; + } + + if (router_uses_map (router) && dst_was_good) + { router_redo_map(router, now); - dst->failed = now; - router->map_failed = now; + router->map_failed = now; + } } // connect to a best destination, possiblly failing over to a next best @@ -575,8 +662,9 @@ } else { // prepare a socket - *sock = glb_socket_create (&router->sock_out, - GLB_SOCK_NODELAY /*| GLB_SOCK_NONBLOCK*/); + uint32_t const ka_opt = router->cnf->keepalive * GLB_SOCK_KEEPALIVE; + + *sock = glb_socket_create (&router->sock_out,GLB_SOCK_NODELAY | ka_opt); if (*sock < 0) { glb_log_error ("glb_socket_create() failed"); @@ -706,6 +794,7 @@ if (len == buf_len) { buf[len - 1] = '\0'; + GLB_MUTEX_UNLOCK (&router->lock); return (len - 1); } } @@ -792,6 +881,7 @@ d->dst.weight, d->map); if (len == buf_len) { buf[len - 1] = '\0'; + GLB_MUTEX_UNLOCK (&router->lock); return (len - 1); } } | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_socket.c ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2012 Codership Oy <info@codership.com> * - * $Id: glb_socket.c 126 2013-01-08 03:36:55Z alex $ + * $Id: glb_socket.c 138 2013-01-18 12:07:31Z alex $ */ #include "glb_socket.h" @@ -150,6 +150,53 @@ } #endif + if ((optflags & GLB_SOCK_KEEPALIVE) && + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one))) + { + glb_log_warn ("Setting TCP_DEFER_ACCEPT failed: %d (%s)", + errno, strerror(errno)); + ret = -errno; + } + else + { +#if defined(TCP_KEEPIDLE) + int idle_seconds = 10; + if (!setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, + &idle_seconds, sizeof(idle_seconds))) + { +#if defined(TCP_KEEPINTVL) + int interval = 5; + if (!setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, + &interval, sizeof(interval))) + { +#if defined(TCP_KEEPCNT) + int tries = 3; + if (setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, + &tries, sizeof(tries))) + { + glb_log_warn ("Setting TCP_KEEPINTVL failed: %d (%s)", + errno, strerror(errno)); + ret = -errno; + } +#endif /* TCP_KEEPCNT */ + } + else + { + glb_log_warn ("Setting TCP_KEEPCNT failed: %d (%s)", + errno, strerror(errno)); + ret = -errno; + } +#endif /* TCP_KEEPINTVL */ + } + else + { + glb_log_warn ("Setting TCP_KEEPIDLE failed: %d (%s)", + errno, strerror(errno)); + ret = -errno; + } +#endif /* TCP_KEEPIDLE */ + } + if ((optflags & GLB_SOCK_NODELAY) && glb_cnf->nodelay && setsockopt(sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { @@ -171,7 +218,7 @@ if ((optflags & GLB_SOCK_NONBLOCK) && glb_fd_set_flag (sock, O_NONBLOCK, true)) { - glb_log_warn ("Setting O_NONBLCK failed: %d (%s)", + glb_log_warn ("Setting O_NONBLOCK failed: %d (%s)", errno, strerror(errno)); ret = -errno; } | ||
[+] | Changed | glb-0.9.2.tar.bz2/src/glb_socket.h ^ |
@@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2012 Codership Oy <info@codership.com> * - * $Id: glb_socket.h 126 2013-01-08 03:36:55Z alex $ + * $Id: glb_socket.h 138 2013-01-18 12:07:31Z alex $ */ #ifndef _glb_socket_h_ @@ -48,6 +48,7 @@ #define GLB_SOCK_NODELAY 1U #define GLB_SOCK_DEFER_ACCEPT 2U #define GLB_SOCK_NONBLOCK 4U +#define GLB_SOCK_KEEPALIVE 8U // Returns socket (file descriptor) bound to a given address // with default options set |