You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

upstream.h 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (c) 2014, Vsevolod Stakhov
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #ifndef UPSTREAM_H_
  26. #define UPSTREAM_H_
  27. #include <time.h>
  28. #include <stdio.h>
  29. /**
  30. * @file upstream.h
  31. * The basic macros to define upstream objects
  32. */
  33. #ifndef upstream_fatal
  34. #define upstream_fatal(msg) do { perror (msg); exit (-1); } while (0)
  35. #endif
  36. #ifndef upstream_malloc
  37. #define upstream_malloc(size) malloc (size)
  38. #endif
  39. #ifndef upstream_free
  40. #define upstream_free(size, ptr) free (ptr)
  41. #endif
  42. struct upstream_entry_s;
  43. struct upstream_common_data {
  44. void **upstreams;
  45. unsigned int allocated_nelts;
  46. unsigned int nelts;
  47. unsigned int alive;
  48. };
  49. typedef struct upstream_entry_s {
  50. unsigned short errors; /**< errors for this upstream */
  51. unsigned short dead;
  52. unsigned short priority;
  53. unsigned short weight;
  54. time_t time; /**< time of marking */
  55. void *parent; /**< parent object */
  56. struct upstream_common_data *common; /**< common data */
  57. void *next; /**< link to the next */
  58. } upstream_entry_t;
  59. /*
  60. * Here we define some reasonable defaults:
  61. * if an upstream has more than `UPSTREAM_MAX_ERRORS` in the period of time
  62. * of `UPSTREAM_ERROR_TIME` then we shut it down for `UPSTREAM_REVIVE_TIME`.
  63. * In this particular case times are 10 seconds for 10 errors and revive in
  64. * 30 seconds.
  65. */
  66. #ifndef UPSTREAM_REVIVE_TIME
  67. #define UPSTREAM_REVIVE_TIME 30
  68. #endif
  69. #ifndef UPSTREAM_ERROR_TIME
  70. #define UPSTREAM_ERROR_TIME 10
  71. #endif
  72. #ifndef UPSTREAM_MAX_ERRORS
  73. #define UPSTREAM_MAX_ERRORS 10
  74. #endif
  75. #define UPSTREAM_FAIL(u, now) do { \
  76. if ((u)->up.time != 0) { \
  77. if ((now) - (u)->up.time >= UPSTREAM_ERROR_TIME) { \
  78. if ((u)->up.errors >= UPSTREAM_MAX_ERRORS) { \
  79. (u)->up.dead = 1; \
  80. (u)->up.time = now; \
  81. (u)->up.common->alive --; \
  82. } \
  83. else { \
  84. (u)->up.errors = 1; \
  85. (u)->up.time = (now); \
  86. } \
  87. } \
  88. else { \
  89. (u)->up.errors ++; \
  90. } \
  91. } \
  92. else { \
  93. (u)->up.errors ++; \
  94. (u)->up.time = (now); \
  95. } \
  96. } while (0)
  97. #define UPSTREAM_OK(u) do { \
  98. (u)->up.errors = 0; \
  99. (u)->up.time = 0; \
  100. } while (0)
  101. #define UPSTREAM_ADD(head, u, priority) do { \
  102. if (head == NULL) { \
  103. struct upstream_common_data *cd; \
  104. cd = upstream_malloc (sizeof (struct upstream_common_data)); \
  105. if (cd == NULL) { \
  106. upstream_fatal ("malloc failed"); \
  107. } \
  108. cd->upstreams = upstream_malloc (sizeof (void *) * 8); \
  109. if (cd == NULL) { \
  110. upstream_fatal ("malloc failed"); \
  111. } \
  112. cd->allocated_nelts = 8; \
  113. cd->nelts = 1; \
  114. cd->alive = 1; \
  115. cd->upstreams[0] = (u); \
  116. (u)->up.common = cd; \
  117. } \
  118. else { \
  119. struct upstream_common_data *cd = (head)->up.common; \
  120. (u)->up.common = cd; \
  121. if (cd->nelts == cd->allocated_nelts) { \
  122. void **nup; \
  123. nup = upstream_malloc (sizeof (void *) * cd->nelts * 2); \
  124. if (nup == NULL) { \
  125. upstream_fatal ("malloc failed"); \
  126. } \
  127. memcpy (nup, cd->upstreams, cd->nelts * sizeof (void *)); \
  128. upstream_free (cd->nelts * sizeof (void *), cd->upstreams); \
  129. cd->upstreams = nup; \
  130. cd->allocated_nelts *= 2; \
  131. } \
  132. cd->upstreams[cd->nelts++] = (u); \
  133. cd->alive ++; \
  134. } \
  135. (u)->up.next = (head); \
  136. (head) = (u); \
  137. if (priority > 0) { \
  138. (u)->up.priority = (u)->up.weight = (priority); \
  139. } \
  140. else { \
  141. (u)->up.priority = (u)->up.weight = 65535; \
  142. } \
  143. (u)->up.time = 0; \
  144. (u)->up.errors = 0; \
  145. (u)->up.dead = 0; \
  146. (u)->up.parent = (u); \
  147. } while (0)
  148. #define UPSTREAM_DEL(head, u) do { \
  149. if (head != NULL) { \
  150. struct upstream_common_data *cd = (head)->up.common; \
  151. if ((u)->up.next != NULL) { \
  152. (head) = (u)->up.next; \
  153. cd->nelts --; \
  154. cd->alive --; \
  155. } \
  156. else { \
  157. upstream_free (cd->allocated_nelts * sizeof (void *), \
  158. cd->upstreams); \
  159. upstream_free (sizeof (struct upstream_common_data), cd); \
  160. (head) = NULL; \
  161. } \
  162. } \
  163. } while (0)
  164. #define UPSTREAM_FOREACH(head, u) for ((u) = (head); (u) != NULL; (u) = (u)->up.next)
  165. #define UPSTREAM_FOREACH_SAFE(head, u, tmp) \
  166. for ((u) = (head); \
  167. (u) != NULL && ((tmp = (u)->up.next) || true); \
  168. (u) = (tmp))
  169. #define UPSTREAM_REVIVE_ALL(head) do { \
  170. __typeof(head) elt = (head); \
  171. while (elt != NULL) { \
  172. elt->up.dead = 0; \
  173. elt->up.errors = 0; \
  174. elt->up.time = 0; \
  175. elt = elt->up.next; \
  176. } \
  177. (head)->up.common->alive = (head)->up.common->nelts; \
  178. } while (0)
  179. #define UPSTREAM_RESCAN(head, now) do { \
  180. __typeof(head) elt = (head); \
  181. if ((head)->up.common->alive == 0) { \
  182. UPSTREAM_REVIVE_ALL((head)); \
  183. } \
  184. else { \
  185. while (elt != NULL) { \
  186. if (elt->up.dead) { \
  187. if ((now) - elt->up.time >= UPSTREAM_REVIVE_TIME) { \
  188. elt->up.dead = 0; \
  189. elt->up.errors = 0; \
  190. elt->up.weight = elt->up.priority; \
  191. (head)->up.common->alive ++; \
  192. } \
  193. } \
  194. else { \
  195. if ((now) - elt->up.time >= UPSTREAM_ERROR_TIME && \
  196. elt->up.errors >= UPSTREAM_MAX_ERRORS) { \
  197. elt->up.dead = 1; \
  198. elt->up.time = now; \
  199. (head)->up.common->alive --; \
  200. } \
  201. } \
  202. elt = elt->up.next; \
  203. } \
  204. } \
  205. } while (0)
  206. #define UPSTREAM_SELECT_ROUND_ROBIN(head, selected) do { \
  207. __typeof(head) elt = (head); \
  208. (selected) = NULL; \
  209. int alive = 0; \
  210. unsigned max_weight = 0; \
  211. if ((head)->up.common->alive == 0){ \
  212. UPSTREAM_REVIVE_ALL(head); \
  213. } \
  214. while (elt != NULL) { \
  215. if (!elt->up.dead) { \
  216. if (elt->up.weight > max_weight) { \
  217. max_weight = elt->up.weight; \
  218. (selected) = elt; \
  219. } \
  220. alive ++; \
  221. } \
  222. elt = elt->up.next; \
  223. } \
  224. if (max_weight == 0) { \
  225. elt = (head); \
  226. while (elt != NULL) { \
  227. elt->up.weight = elt->up.priority; \
  228. if (!elt->up.dead) { \
  229. if (elt->up.priority > max_weight) { \
  230. max_weight = elt->up.priority; \
  231. (selected) = elt; \
  232. } \
  233. } \
  234. elt = elt->up.next; \
  235. } \
  236. } \
  237. (selected)->up.weight --; \
  238. } while (0)
  239. #endif /* UPSTREAM_H_ */