123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*
- * Copyright (c) 2014, Vsevolod Stakhov
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
- #ifndef UPSTREAM_H_
- #define UPSTREAM_H_
-
- #include <time.h>
- #include <stdio.h>
-
- /**
- * @file upstream.h
- * The basic macros to define upstream objects
- */
-
- #ifndef upstream_fatal
- #define upstream_fatal(msg) do { perror (msg); exit (-1); } while (0)
- #endif
-
- #ifndef upstream_malloc
- #define upstream_malloc(size) malloc (size)
- #endif
-
- #ifndef upstream_free
- #define upstream_free(size, ptr) free (ptr)
- #endif
-
- struct upstream_entry_s;
- struct upstream_common_data {
- void **upstreams;
- unsigned int allocated_nelts;
- unsigned int nelts;
- unsigned int alive;
- };
-
- typedef struct upstream_entry_s {
- unsigned short errors; /**< errors for this upstream */
- unsigned short dead;
- unsigned short priority;
- unsigned short weight;
- time_t time; /**< time of marking */
- void *parent; /**< parent object */
- struct upstream_common_data *common; /**< common data */
- void *next; /**< link to the next */
- } upstream_entry_t;
-
- /*
- * Here we define some reasonable defaults:
- * if an upstream has more than `UPSTREAM_MAX_ERRORS` in the period of time
- * of `UPSTREAM_ERROR_TIME` then we shut it down for `UPSTREAM_REVIVE_TIME`.
- * In this particular case times are 10 seconds for 10 errors and revive in
- * 30 seconds.
- */
- #ifndef UPSTREAM_REVIVE_TIME
- #define UPSTREAM_REVIVE_TIME 30
- #endif
- #ifndef UPSTREAM_ERROR_TIME
- #define UPSTREAM_ERROR_TIME 10
- #endif
- #ifndef UPSTREAM_MAX_ERRORS
- #define UPSTREAM_MAX_ERRORS 10
- #endif
-
- #define UPSTREAM_FAIL(u, now) do { \
- if ((u)->up.time != 0) { \
- if ((now) - (u)->up.time >= UPSTREAM_ERROR_TIME) { \
- if ((u)->up.errors >= UPSTREAM_MAX_ERRORS) { \
- (u)->up.dead = 1; \
- (u)->up.time = now; \
- (u)->up.common->alive --; \
- } \
- else { \
- (u)->up.errors = 1; \
- (u)->up.time = (now); \
- } \
- } \
- else { \
- (u)->up.errors ++; \
- } \
- } \
- else { \
- (u)->up.errors ++; \
- (u)->up.time = (now); \
- } \
- } while (0)
-
- #define UPSTREAM_OK(u) do { \
- (u)->up.errors = 0; \
- (u)->up.time = 0; \
- } while (0)
-
- #define UPSTREAM_ADD(head, u, priority) do { \
- if (head == NULL) { \
- struct upstream_common_data *cd; \
- cd = upstream_malloc (sizeof (struct upstream_common_data)); \
- if (cd == NULL) { \
- upstream_fatal ("malloc failed"); \
- } \
- cd->upstreams = upstream_malloc (sizeof (void *) * 8); \
- if (cd == NULL) { \
- upstream_fatal ("malloc failed"); \
- } \
- cd->allocated_nelts = 8; \
- cd->nelts = 1; \
- cd->alive = 1; \
- cd->upstreams[0] = (u); \
- (u)->up.common = cd; \
- } \
- else { \
- struct upstream_common_data *cd = (head)->up.common; \
- (u)->up.common = cd; \
- if (cd->nelts == cd->allocated_nelts) { \
- void **nup; \
- nup = upstream_malloc (sizeof (void *) * cd->nelts * 2); \
- if (nup == NULL) { \
- upstream_fatal ("malloc failed"); \
- } \
- memcpy (nup, cd->upstreams, cd->nelts * sizeof (void *)); \
- upstream_free (cd->nelts * sizeof (void *), cd->upstreams); \
- cd->upstreams = nup; \
- cd->allocated_nelts *= 2; \
- } \
- cd->upstreams[cd->nelts++] = (u); \
- cd->alive ++; \
- } \
- (u)->up.next = (head); \
- (head) = (u); \
- if (priority > 0) { \
- (u)->up.priority = (u)->up.weight = (priority); \
- } \
- else { \
- (u)->up.priority = (u)->up.weight = 65535; \
- } \
- (u)->up.time = 0; \
- (u)->up.errors = 0; \
- (u)->up.dead = 0; \
- (u)->up.parent = (u); \
- } while (0)
-
- #define UPSTREAM_DEL(head, u) do { \
- if (head != NULL) { \
- struct upstream_common_data *cd = (head)->up.common; \
- if ((u)->up.next != NULL) { \
- (head) = (u)->up.next; \
- cd->nelts --; \
- cd->alive --; \
- } \
- else { \
- upstream_free (cd->allocated_nelts * sizeof (void *), \
- cd->upstreams); \
- upstream_free (sizeof (struct upstream_common_data), cd); \
- (head) = NULL; \
- } \
- } \
- } while (0)
-
- #define UPSTREAM_FOREACH(head, u) for ((u) = (head); (u) != NULL; (u) = (u)->up.next)
- #define UPSTREAM_FOREACH_SAFE(head, u, tmp) \
- for ((u) = (head); \
- (u) != NULL && ((tmp = (u)->up.next) || true); \
- (u) = (tmp))
-
- #define UPSTREAM_REVIVE_ALL(head) do { \
- __typeof(head) elt = (head); \
- while (elt != NULL) { \
- elt->up.dead = 0; \
- elt->up.errors = 0; \
- elt->up.time = 0; \
- elt = elt->up.next; \
- } \
- (head)->up.common->alive = (head)->up.common->nelts; \
- } while (0)
-
- #define UPSTREAM_RESCAN(head, now) do { \
- __typeof(head) elt = (head); \
- if ((head)->up.common->alive == 0) { \
- UPSTREAM_REVIVE_ALL((head)); \
- } \
- else { \
- while (elt != NULL) { \
- if (elt->up.dead) { \
- if ((now) - elt->up.time >= UPSTREAM_REVIVE_TIME) { \
- elt->up.dead = 0; \
- elt->up.errors = 0; \
- elt->up.weight = elt->up.priority; \
- (head)->up.common->alive ++; \
- } \
- } \
- else { \
- if ((now) - elt->up.time >= UPSTREAM_ERROR_TIME && \
- elt->up.errors >= UPSTREAM_MAX_ERRORS) { \
- elt->up.dead = 1; \
- elt->up.time = now; \
- (head)->up.common->alive --; \
- } \
- } \
- elt = elt->up.next; \
- } \
- } \
- } while (0)
-
- #define UPSTREAM_SELECT_ROUND_ROBIN(head, selected) do { \
- __typeof(head) elt = (head); \
- (selected) = NULL; \
- int alive = 0; \
- unsigned max_weight = 0; \
- if ((head)->up.common->alive == 0){ \
- UPSTREAM_REVIVE_ALL(head); \
- } \
- while (elt != NULL) { \
- if (!elt->up.dead) { \
- if (elt->up.weight > max_weight) { \
- max_weight = elt->up.weight; \
- (selected) = elt; \
- } \
- alive ++; \
- } \
- elt = elt->up.next; \
- } \
- if (max_weight == 0) { \
- elt = (head); \
- while (elt != NULL) { \
- elt->up.weight = elt->up.priority; \
- if (!elt->up.dead) { \
- if (elt->up.priority > max_weight) { \
- max_weight = elt->up.priority; \
- (selected) = elt; \
- } \
- } \
- elt = elt->up.next; \
- } \
- } \
- (selected)->up.weight --; \
- } while (0)
-
- #endif /* UPSTREAM_H_ */
|