Index: trunk/willow/src/include/wbackend.h |
— | — | @@ -58,6 +58,7 @@ |
59 | 59 | backend_list( backend_pool const &pool, |
60 | 60 | imstring const &url, |
61 | 61 | imstring const &host, |
| 62 | + int failgroup, |
62 | 63 | lb_type, int start); |
63 | 64 | |
64 | 65 | int _get_impl (polycallback<backend *, wsocket *>); |
— | — | @@ -65,6 +66,9 @@ |
66 | 67 | struct backend *_next_backend (void); |
67 | 68 | void _carp_recalc (imstring const &, imstring const &, lb_type); |
68 | 69 | static int _becarp_cmp (backend const *a, backend const *b); |
| 70 | + bool failed (void) const { |
| 71 | + return _delegate; |
| 72 | + } |
69 | 73 | |
70 | 74 | template<typename stringT> |
71 | 75 | static uint32_t _carp_urlhash(stringT const &str) { |
— | — | @@ -81,9 +85,16 @@ |
82 | 86 | return _get_impl(polycallback<backend *, wsocket *>(cb, t)); |
83 | 87 | } |
84 | 88 | |
| 89 | + ~backend_list() { |
| 90 | + if (_delegate) |
| 91 | + delete _delegate; |
| 92 | + } |
| 93 | + |
85 | 94 | private: |
86 | 95 | vector<backend *, pt_allocator<backend *> > backends; |
87 | | - size_t _cur; |
| 96 | + size_t _cur; |
| 97 | + int _failgroup; |
| 98 | + struct backend_list *_delegate; |
88 | 99 | }; |
89 | 100 | |
90 | 101 | template<typename stringT> |
— | — | @@ -95,7 +106,7 @@ |
96 | 107 | } |
97 | 108 | |
98 | 109 | struct backend_pool { |
99 | | - backend_pool(string const &name, lb_type); |
| 110 | + backend_pool(string const &name, lb_type, int failgroup = -1); |
100 | 111 | ~backend_pool(); |
101 | 112 | |
102 | 113 | void add (string const &, int, int); |
— | — | @@ -118,6 +129,7 @@ |
119 | 130 | tss<size_t> _cur; |
120 | 131 | lb_type _lbtype; |
121 | 132 | string _name; |
| 133 | + int _failgroup; |
122 | 134 | }; |
123 | 135 | |
124 | 136 | extern map<int, backend_pool> bpools; |
Index: trunk/willow/src/willow/wconfig.cc |
— | — | @@ -303,7 +303,7 @@ |
304 | 304 | void |
305 | 305 | set_backend_group(tree_entry &e) |
306 | 306 | { |
307 | | -int gn; |
| 307 | +int gn, fogroup = -1; |
308 | 308 | string group; |
309 | 309 | map<string, int>::iterator it; |
310 | 310 | group = e.item_key; |
— | — | @@ -327,8 +327,16 @@ |
328 | 328 | lbtype = lb_carp_hostonly; |
329 | 329 | } |
330 | 330 | |
| 331 | + if ((v = e/"failover-group") != NULL) { |
| 332 | + if ((it = poolnames.find(v->cv_values[0].av_strval)) == poolnames.end()) { |
| 333 | + v->report_error("failover-group does not exist"); |
| 334 | + } else { |
| 335 | + fogroup = it->second; |
| 336 | + } |
| 337 | + } |
| 338 | + |
331 | 339 | WDEBUG((WLOG_DEBUG, format("adding backend %d type = %d") % gn % (int) lbtype)); |
332 | | - bpools.insert(make_pair(gn, backend_pool(e.item_key, lbtype))); |
| 340 | + bpools.insert(make_pair(gn, backend_pool(e.item_key, lbtype, fogroup))); |
333 | 341 | |
334 | 342 | if ((v = e/"hosts") != NULL) { |
335 | 343 | vector<avalue>::iterator it = v->cv_values.begin(), end = v->cv_values.end(); |
— | — | @@ -409,8 +417,9 @@ |
410 | 418 | |
411 | 419 | .block("backend-group", require_name) |
412 | 420 | .end(func(set_backend_group)) |
413 | | - .value("lb-type", func(v_lb_type), ignore) |
414 | | - .value("hosts", func(v_hosts), ignore) |
| 421 | + .value("lb-type", func(v_lb_type), ignore) |
| 422 | + .value("hosts", func(v_hosts), ignore) |
| 423 | + .value("failover-group", nonempty_qstring, ignore) |
415 | 424 | |
416 | 425 | .block("backend", require_name) |
417 | 426 | .end(func(set_backend)) |
Index: trunk/willow/src/willow/whttp.cc |
— | — | @@ -263,8 +263,6 @@ |
264 | 264 | _chunking_filter = NULL; |
265 | 265 | delete _size_limit; |
266 | 266 | _size_limit = NULL; |
267 | | - delete _blist; |
268 | | - _blist = NULL; |
269 | 267 | delete _header_parser; |
270 | 268 | _header_parser = NULL; |
271 | 269 | |
— | — | @@ -272,13 +270,15 @@ |
273 | 271 | * Return the backend to the keepalive pool, if we can. |
274 | 272 | */ |
275 | 273 | if (_backend_socket && !_backend_headers->_no_keepalive && |
276 | | - _backend_headers->_http_vers == http11) { |
| 274 | + _backend_headers->_http_vers == http11 && (!_blist || !_blist->failed())) { |
277 | 275 | bpools.find(_group)->second.add_keptalive( |
278 | 276 | make_pair(_backend_socket, _backend)); |
279 | 277 | } else { |
280 | 278 | delete _backend_socket; |
281 | 279 | } |
282 | 280 | |
| 281 | + delete _blist; |
| 282 | + _blist = NULL; |
283 | 283 | _backend_socket = NULL; |
284 | 284 | delete _backend_headers; |
285 | 285 | _backend_headers = NULL; |
Index: trunk/willow/src/willow/wbackend.cc |
— | — | @@ -58,9 +58,10 @@ |
59 | 59 | % be_straddr % be_hash)); |
60 | 60 | } |
61 | 61 | |
62 | | -backend_pool::backend_pool(string const &name, lb_type lbt) |
| 62 | +backend_pool::backend_pool(string const &name, lb_type lbt, int failgroup) |
63 | 63 | : _lbtype(lbt) |
64 | 64 | , _name(name) |
| 65 | + , _failgroup(failgroup) |
65 | 66 | { |
66 | 67 | WDEBUG((WLOG_DEBUG, format("creating backend_pool, lbt=%d") % (int) lbt)); |
67 | 68 | } |
— | — | @@ -97,6 +98,12 @@ |
98 | 99 | static time_t last_nfile; |
99 | 100 | time_t now = time(NULL); |
100 | 101 | |
| 102 | + /* |
| 103 | + * If we're delegating (for failover), pass this request off. |
| 104 | + */ |
| 105 | + if (_delegate) |
| 106 | + return _delegate->_get_impl(cb); |
| 107 | + |
101 | 108 | cbd = new backend_cb_data; |
102 | 109 | cbd->bc_func = cb; |
103 | 110 | |
— | — | @@ -104,7 +111,15 @@ |
105 | 112 | cbd->bc_backend = _next_backend(); |
106 | 113 | |
107 | 114 | if (cbd->bc_backend == NULL) { |
| 115 | + /* |
| 116 | + * All out of backends. See if we have a failover |
| 117 | + * group to try. |
| 118 | + */ |
108 | 119 | delete cbd; |
| 120 | + if (_failgroup != -1) { |
| 121 | + _delegate = bpools.find(_failgroup)->second.get_list("", ""); |
| 122 | + return _delegate->_get_impl(cb); |
| 123 | + } |
109 | 124 | return -1; |
110 | 125 | } |
111 | 126 | |
— | — | @@ -179,11 +194,14 @@ |
180 | 195 | backend_pool const &bp, |
181 | 196 | imstring const &url, |
182 | 197 | imstring const &host, |
| 198 | + int failgroup, |
183 | 199 | lb_type lbt, |
184 | 200 | int cur) |
185 | 201 | |
186 | 202 | : backends(bp.backends) |
187 | 203 | , _cur(0) |
| 204 | + , _failgroup(failgroup) |
| 205 | + , _delegate(NULL) |
188 | 206 | { |
189 | 207 | WDEBUG((WLOG_DEBUG, format("lbt = %d") % (int)lbt)); |
190 | 208 | rotate(backends.begin(), backends.begin() + cur, backends.end()); |
— | — | @@ -205,7 +223,7 @@ |
206 | 224 | if (*_cur >= backends.size()) |
207 | 225 | *_cur = 0; |
208 | 226 | |
209 | | - return new backend_list(*this, url, host, _lbtype, (*_cur)++); |
| 227 | + return new backend_list(*this, url, host, _failgroup, _lbtype, (*_cur)++); |
210 | 228 | } |
211 | 229 | |
212 | 230 | struct backend * |
— | — | @@ -216,9 +234,6 @@ |
217 | 235 | while (tried++ <= backends.size()) { |
218 | 236 | time_t now = time(NULL); |
219 | 237 | |
220 | | - WDEBUG((WLOG_DEBUG, format("_next_backend: considering %d %s") |
221 | | - % _cur % backends[_cur]->be_name)); |
222 | | - |
223 | 238 | if (_cur >= backends.size()) |
224 | 239 | _cur = 0; |
225 | 240 | |
Index: trunk/willow/willow.conf.example |
— | — | @@ -52,7 +52,13 @@ |
53 | 53 | port = 8081; |
54 | 54 | }; |
55 | 55 | |
56 | | -backend-group "backup" { |
| 56 | +/* A place to send requests for which no backend was found */ |
| 57 | +backend-group "failover"; |
| 58 | +backend "failover.mycompany.com" { |
| 59 | + group = "failover"; |
| 60 | +}; |
| 61 | + |
| 62 | +backend-group "primary" { |
57 | 63 | /* |
58 | 64 | * lb-type can be "rr" (plain roundrobin), "carp" (use CARP |
59 | 65 | * algorithm) or "carp-host" (use CARP but only consider the |
— | — | @@ -65,6 +71,12 @@ |
66 | 72 | * matter which listener received the request. |
67 | 73 | */ |
68 | 74 | hosts = "www.bar.com", "www2.bar.com"; |
| 75 | + |
| 76 | + /* |
| 77 | + * If all backends in the group are down, send requests to this |
| 78 | + * group instead. |
| 79 | + */ |
| 80 | + failover-group = "failover"; |
69 | 81 | }; |
70 | 82 | |
71 | 83 | backend "backends.mycompany.com" { |
— | — | @@ -79,7 +91,7 @@ |
80 | 92 | * also has this group, requests to that listener will only |
81 | 93 | * go to backends in that group. |
82 | 94 | */ |
83 | | - group = "backup"; |
| 95 | + group = "primary"; |
84 | 96 | }; |
85 | 97 | |
86 | 98 | /* |