Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 3733 lines (3066 sloc) 116.857 kB
137d5bc @steveyen cproxy_init takes config string input
steveyen authored
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
b9242d3 @steveyen MB-2689 - add timeout to moxi SASL auth & bucket select requests
steveyen authored
2
6fcace5 @trondn Move to pandora build
trondn authored
3 #include "config.h"
052bcc3 @steveyen started cproxy.c/h
steveyen authored
4 #include <stdio.h>
0577ccb @steveyen avoid libmemcached dependency
steveyen authored
5 #include <stdlib.h>
a0cf967 @steveyen parsing cproxy init cfg
steveyen authored
6 #include <string.h>
2b1fec0 @steveyen Made server_socket() exposed for reuse by cproxy.
steveyen authored
7 #include <errno.h>
2a49e4f @steveyen started func_work list
steveyen authored
8 #include <pthread.h>
c6fa4d0 @steveyen cproxy_start function
steveyen authored
9 #include <assert.h>
5b8996b @steveyen WIP - zstored connection pooling functions
steveyen authored
10 #include <fcntl.h>
68caea9 @steveyen upstream timeout fix
steveyen authored
11 #include <math.h>
052bcc3 @steveyen started cproxy.c/h
steveyen authored
12 #include "memcached.h"
13 #include "cproxy.h"
b182daf @steveyen refactored work_queue into separate work.c/.h files
steveyen authored
14 #include "work.h"
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
15 #include "log.h"
052bcc3 @steveyen started cproxy.c/h
steveyen authored
16
5c5feba @steveyen bug 2337, moved MOXI_BLOCKING_CONNECT definition
steveyen authored
17 #ifndef MOXI_BLOCKING_CONNECT
18 #define MOXI_BLOCKING_CONNECT false
19 #endif
20
24042d2 @steveyen moved protocol handling stuff into cproxy_protocol.c
steveyen authored
21 // Internal forward declarations.
4ba2e17 @steveyen moved stuff to cproxy.h
steveyen authored
22 //
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
23 downstream *downstream_list_remove(downstream *head, downstream *d);
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
24 downstream *downstream_list_waiting_remove(downstream *head,
25 downstream **tail,
26 downstream *d);
3934e62 @steveyen auth_downstream first implementation
steveyen authored
27
bcd9961 @steveyen init_memcached_st() helper func for drain/fill
steveyen authored
28 void downstream_timeout(const int fd,
29 const short which,
30 void *arg);
31 void wait_queue_timeout(const int fd,
32 const short which,
33 void *arg);
34
3934e62 @steveyen auth_downstream first implementation
steveyen authored
35 conn *conn_list_remove(conn *head, conn **tail,
36 conn *c, bool *found);
37
bcd9961 @steveyen init_memcached_st() helper func for drain/fill
steveyen authored
38 bool is_compatible_request(conn *existing, conn *candidate);
39
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
40 void propagate_error_msg(downstream *d, char *ascii_msg,
41 protocol_binary_response_status binary_status);
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
42
0739827 @steveyen downstreaming timing histogram
steveyen authored
43 void downstream_reserved_time_sample(proxy_stats_td *ptds, uint64_t duration);
83361a6 @steveyen added histogram for connect times
steveyen authored
44 void downstream_connect_time_sample(proxy_stats_td *ptds, uint64_t duration);
0739827 @steveyen downstreaming timing histogram
steveyen authored
45
6847773 @steveyen cproxy_connect_downstream_conn() now calls mcs_connect()
steveyen authored
46 bool downstream_connect_init(downstream *d, mcs_server_st *msst,
47 proxy_behavior *behavior, conn *c);
48
1faf3af @steveyen bug 2605 - propagate usr/pwd correctly to mcs layer
steveyen authored
49 int init_mcs_st(mcs_st *mst, char *config,
50 const char *default_usr,
167ac24 @steveyen MB-3798 - moxi option for ketama/weighted/modula item distributions
steveyen authored
51 const char *default_pwd,
52 const char *opts);
3934e62 @steveyen auth_downstream first implementation
steveyen authored
53
e570e03 @steveyen allow conn_connect callback to control drive_machine() loop
steveyen authored
54 bool cproxy_on_connect_downstream_conn(conn *c);
5b8996b @steveyen WIP - zstored connection pooling functions
steveyen authored
55
56 conn *zstored_acquire_downstream_conn(downstream *d,
57 LIBEVENT_THREAD *thread,
58 mcs_server_st *msst,
742ea0f @steveyen check for downstream_conn_max to limit number of connections
steveyen authored
59 proxy_behavior *behavior,
60 bool *downstream_conn_max_reached);
5b8996b @steveyen WIP - zstored connection pooling functions
steveyen authored
61
62 void zstored_release_downstream_conn(conn *dc, bool closing);
63
6dafe70 @steveyen checking MAX_DOWNSTREAM_CONNECTION_ERRORS and DOWNSTREAM_RETRY_INTERVAL
steveyen authored
64 void zstored_error_count(LIBEVENT_THREAD *thread,
d612be0 @steveyen bug 2237 - calling zstored_error_count() more during errors
steveyen authored
65 const char *host_ident,
6dafe70 @steveyen checking MAX_DOWNSTREAM_CONNECTION_ERRORS and DOWNSTREAM_RETRY_INTERVAL
steveyen authored
66 bool has_error);
67
742ea0f @steveyen check for downstream_conn_max to limit number of connections
steveyen authored
68 bool zstored_downstream_waiting_add(downstream *d, LIBEVENT_THREAD *thread,
69 mcs_server_st *msst,
70 proxy_behavior *behavior);
71
026a9b7 @steveyen MB-2825 - downstream_conn_queue_timeout
steveyen authored
72 bool zstored_downstream_waiting_remove(downstream *d);
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
73
6dafe70 @steveyen checking MAX_DOWNSTREAM_CONNECTION_ERRORS and DOWNSTREAM_RETRY_INTERVAL
steveyen authored
74 typedef struct {
742ea0f @steveyen check for downstream_conn_max to limit number of connections
steveyen authored
75 conn *dc; // Linked-list of available downstream conns.
76 uint32_t dc_acquired; // Count of acquired (in-use) downstream conns.
6dafe70 @steveyen checking MAX_DOWNSTREAM_CONNECTION_ERRORS and DOWNSTREAM_RETRY_INTERVAL
steveyen authored
77 char *host_ident;
58e3c07 @steveyen connect timeout and retry interval are now runtime configurable
steveyen authored
78 uint32_t error_count;
6a26e91 @steveyen MB-2897 - use 64-bits for msec_current time
steveyen authored
79 uint64_t error_time;
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
80
81 // Head & tail of singly linked-list/queue, using
82 // downstream->next_waiting pointers, where we've reached
83 // downstream_conn_max, so there are waiting downstreams.
84 //
85 downstream *downstream_waiting_head;
86 downstream *downstream_waiting_tail;
6dafe70 @steveyen checking MAX_DOWNSTREAM_CONNECTION_ERRORS and DOWNSTREAM_RETRY_INTERVAL
steveyen authored
87 } zstored_downstream_conns;
88
d612be0 @steveyen bug 2237 - calling zstored_error_count() more during errors
steveyen authored
89 zstored_downstream_conns *zstored_get_downstream_conns(LIBEVENT_THREAD *thread,
90 const char *host_ident);
91
19d69af @steveyen cproxy_forward_or_error
steveyen authored
92 bool cproxy_forward_or_error(downstream *d);
93
204bfca @steveyen cproxy_on_connect_downstream_conn hooked up
steveyen authored
94 int delink_from_downstream_conns(conn *c);
95
c25d4e6 @steveyen MB-3113 - close new upstream conns when there are no buckets
steveyen authored
96 int cproxy_num_active_proxies(proxy_main *m);
97
4ba2e17 @steveyen moved stuff to cproxy.h
steveyen authored
98 // Function tables.
99 //
b1880bd @steveyen split out cproxy_listen_funcs into separate array
steveyen authored
100 conn_funcs cproxy_listen_funcs = {
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
101 .conn_init = cproxy_init_upstream_conn,
102 .conn_close = NULL,
9d31ebf @steveyen added conn_connecting state
steveyen authored
103 .conn_connect = NULL,
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
104 .conn_process_ascii_command = NULL,
105 .conn_process_binary_command = NULL,
40a171b @steveyen another conn function in preparation for downstream binary protocol
steveyen authored
106 .conn_complete_nread_ascii = NULL,
107 .conn_complete_nread_binary = NULL,
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
108 .conn_pause = NULL,
220c584 @steveyen conn_binary_command_magic
steveyen authored
109 .conn_realtime = NULL,
498dc88 @steveyen bug 1685 - added stats
steveyen authored
110 .conn_state_change = NULL,
220c584 @steveyen conn_binary_command_magic
steveyen authored
111 .conn_binary_command_magic = 0
b1880bd @steveyen split out cproxy_listen_funcs into separate array
steveyen authored
112 };
113
114 conn_funcs cproxy_upstream_funcs = {
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
115 .conn_init = NULL,
116 .conn_close = cproxy_on_close_upstream_conn,
9d31ebf @steveyen added conn_connecting state
steveyen authored
117 .conn_connect = NULL,
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
118 .conn_process_ascii_command = cproxy_process_upstream_ascii,
d785d2d @steveyen b2b upstream & downstream for simple, non-quiet commands
steveyen authored
119 .conn_process_binary_command = cproxy_process_upstream_binary,
40a171b @steveyen another conn function in preparation for downstream binary protocol
steveyen authored
120 .conn_complete_nread_ascii = cproxy_process_upstream_ascii_nread,
d785d2d @steveyen b2b upstream & downstream for simple, non-quiet commands
steveyen authored
121 .conn_complete_nread_binary = cproxy_process_upstream_binary_nread,
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
122 .conn_pause = NULL,
220c584 @steveyen conn_binary_command_magic
steveyen authored
123 .conn_realtime = cproxy_realtime,
498dc88 @steveyen bug 1685 - added stats
steveyen authored
124 .conn_state_change = cproxy_upstream_state_change,
220c584 @steveyen conn_binary_command_magic
steveyen authored
125 .conn_binary_command_magic = PROTOCOL_BINARY_REQ
38d5472 @steveyen hooking up cproxy_init_conn
steveyen authored
126 };
127
128 conn_funcs cproxy_downstream_funcs = {
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
129 .conn_init = cproxy_init_downstream_conn,
130 .conn_close = cproxy_on_close_downstream_conn,
204bfca @steveyen cproxy_on_connect_downstream_conn hooked up
steveyen authored
131 .conn_connect = cproxy_on_connect_downstream_conn,
d785d2d @steveyen b2b upstream & downstream for simple, non-quiet commands
steveyen authored
132 .conn_process_ascii_command = cproxy_process_downstream_ascii,
133 .conn_process_binary_command = cproxy_process_downstream_binary,
134 .conn_complete_nread_ascii = cproxy_process_downstream_ascii_nread,
135 .conn_complete_nread_binary = cproxy_process_downstream_binary_nread,
dd3e0c3 @steveyen using self-documenting struct init idiom
steveyen authored
136 .conn_pause = cproxy_on_pause_downstream_conn,
220c584 @steveyen conn_binary_command_magic
steveyen authored
137 .conn_realtime = cproxy_realtime,
498dc88 @steveyen bug 1685 - added stats
steveyen authored
138 .conn_state_change = NULL,
220c584 @steveyen conn_binary_command_magic
steveyen authored
139 .conn_binary_command_magic = PROTOCOL_BINARY_RES
38d5472 @steveyen hooking up cproxy_init_conn
steveyen authored
140 };
141
24042d2 @steveyen moved protocol handling stuff into cproxy_protocol.c
steveyen authored
142 /* Main function to create a proxy struct.
143 */
2bebd7a @steveyen added proxy_main ptr to the proxy struct
steveyen authored
144 proxy *cproxy_create(proxy_main *main,
145 char *name,
44353a5 @steveyen refactor misc config slots into a proxy_behavior struct
steveyen authored
146 int port,
147 char *config,
7209ef6 @steveyen added timeout to proxy config
steveyen authored
148 uint32_t config_ver,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
149 proxy_behavior_pool *behavior_pool,
8a7e4b6 @steveyen Moved nthreads out of proxy_behavior.
steveyen authored
150 int nthreads) {
b57db84 @steveyen bug 2592 - extra case of reading bucket pswd from JSON
steveyen authored
151 if (settings.verbose > 1) {
152 moxi_log_write("cproxy_create on port %d, name %s, config %s\n",
153 port, name, config);
154 }
155
14c6d18 @steveyen compiles with memagent
steveyen authored
156 assert(name != NULL);
1b40490 @mtaneja fix support for unix domain sockets
mtaneja authored
157 assert(port > 0 || settings.socketpath != NULL);
c6fa4d0 @steveyen cproxy_start function
steveyen authored
158 assert(config != NULL);
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
159 assert(behavior_pool);
8a7e4b6 @steveyen Moved nthreads out of proxy_behavior.
steveyen authored
160 assert(nthreads > 1); // Main thread + at least one worker.
161 assert(nthreads == settings.num_threads);
c6fa4d0 @steveyen cproxy_start function
steveyen authored
162
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
163 proxy *p = (proxy *) calloc(1, sizeof(proxy));
c6fa4d0 @steveyen cproxy_start function
steveyen authored
164 if (p != NULL) {
2bebd7a @steveyen added proxy_main ptr to the proxy struct
steveyen authored
165 p->main = main;
947c762 @steveyen trimstr()
steveyen authored
166 p->name = trimstrdup(name);
31124eb @steveyen snapshot of config and config_ver in downstream
steveyen authored
167 p->port = port;
947c762 @steveyen trimstr()
steveyen authored
168 p->config = trimstrdup(config);
da4d206 @steveyen better config_ver handling, which is now a uint32_t
steveyen authored
169 p->config_ver = config_ver;
005a5e1 @steveyen added sasl_mech/auth to proxy behavior, which is now more inheritable
steveyen authored
170
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
171 p->behavior_pool.base = behavior_pool->base;
172 p->behavior_pool.num = behavior_pool->num;
173 p->behavior_pool.arr = cproxy_copy_behaviors(behavior_pool->num,
174 behavior_pool->arr);
6259111 @steveyen more proxy stats
steveyen authored
175
176 p->listening = 0;
177 p->listening_failed = 0;
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
178
a49bb8a @steveyen front_cache_lock, with front_cache moved to proxy
steveyen authored
179 p->next = NULL;
180
aa9f46b @steveyen refactored to mcache struct and api functions
steveyen authored
181 pthread_mutex_init(&p->proxy_lock, NULL);
a49bb8a @steveyen front_cache_lock, with front_cache moved to proxy
steveyen authored
182
ac8ee0c @steveyen key_stat funcs work better, and mcache.key_alloc flag
steveyen authored
183 mcache_init(&p->front_cache, true, &mcache_item_funcs, true);
5971996 @steveyen matcher refactor with lock
steveyen authored
184 matcher_init(&p->front_cache_matcher, true);
30e7a4a @steveyen added unmatcher for front cache and key stats
steveyen authored
185 matcher_init(&p->front_cache_unmatcher, true);
e5910ca @steveyen started key_stats
steveyen authored
186
5971996 @steveyen matcher refactor with lock
steveyen authored
187 matcher_init(&p->optimize_set_matcher, true);
188
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
189 if (behavior_pool->base.front_cache_max > 0 &&
190 behavior_pool->base.front_cache_lifespan > 0) {
3f95ed5 @steveyen configurable max number of front cache items
steveyen authored
191 mcache_start(&p->front_cache,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
192 behavior_pool->base.front_cache_max);
66b7400 @steveyen pulled matcher out of mcache
steveyen authored
193
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
194 if (strlen(behavior_pool->base.front_cache_spec) > 0) {
5971996 @steveyen matcher refactor with lock
steveyen authored
195 matcher_start(&p->front_cache_matcher,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
196 behavior_pool->base.front_cache_spec);
66b7400 @steveyen pulled matcher out of mcache
steveyen authored
197 }
30e7a4a @steveyen added unmatcher for front cache and key stats
steveyen authored
198
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
199 if (strlen(behavior_pool->base.front_cache_unspec) > 0) {
30e7a4a @steveyen added unmatcher for front cache and key stats
steveyen authored
200 matcher_start(&p->front_cache_unmatcher,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
201 behavior_pool->base.front_cache_unspec);
30e7a4a @steveyen added unmatcher for front cache and key stats
steveyen authored
202 }
66b7400 @steveyen pulled matcher out of mcache
steveyen authored
203 }
ceb2517 @steveyen front_cache_start/stop()
steveyen authored
204
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
205 if (strlen(behavior_pool->base.optimize_set) > 0) {
5971996 @steveyen matcher refactor with lock
steveyen authored
206 matcher_start(&p->optimize_set_matcher,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
207 behavior_pool->base.optimize_set);
5971996 @steveyen matcher refactor with lock
steveyen authored
208 }
209
8a7e4b6 @steveyen Moved nthreads out of proxy_behavior.
steveyen authored
210 p->thread_data_num = nthreads;
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
211 p->thread_data = (proxy_td *) calloc(p->thread_data_num,
212 sizeof(proxy_td));
005a5e1 @steveyen added sasl_mech/auth to proxy behavior, which is now more inheritable
steveyen authored
213 if (p->thread_data != NULL &&
214 p->name != NULL &&
215 p->config != NULL &&
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
216 p->behavior_pool.arr != NULL) {
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
217 // We start at 1, because thread[0] is the main listen/accept
de57975 @steveyen more comments
steveyen authored
218 // thread, and not a true worker thread. Too lazy to save
219 // the wasted thread[0] slot memory.
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
220 //
2571b05 @steveyen moved work_queue into thread.c for proper, early initialization
steveyen authored
221 for (int i = 1; i < p->thread_data_num; i++) {
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
222 proxy_td *ptd = &p->thread_data[i];
223 ptd->proxy = p;
88ab7db @steveyen keeping config snapshot at proxy_td level for fewer locks
steveyen authored
224
0761324 @steveyen refactored out mcs.h and more docs
steveyen authored
225 ptd->config = strdup(p->config);
226 ptd->config_ver = p->config_ver;
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
227
228 ptd->behavior_pool.base = behavior_pool->base;
229 ptd->behavior_pool.num = behavior_pool->num;
230 ptd->behavior_pool.arr =
231 cproxy_copy_behaviors(behavior_pool->num,
232 behavior_pool->arr);
88ab7db @steveyen keeping config snapshot at proxy_td level for fewer locks
steveyen authored
233
33f8cad @steveyen renamed waiting_for_downstream to waiting_any_downstream for clarity
steveyen authored
234 ptd->waiting_any_downstream_head = NULL;
235 ptd->waiting_any_downstream_tail = NULL;
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
236 ptd->downstream_reserved = NULL;
237 ptd->downstream_released = NULL;
c96d0ef @steveyen tracking downstream_tot in proxy_td
steveyen authored
238 ptd->downstream_tot = 0;
f7e9500 @steveyen added work_queue to proxy_ptd
steveyen authored
239 ptd->downstream_num = 0;
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
240 ptd->downstream_max = behavior_pool->base.downstream_max;
beac84d @steveyen recursion safety check
steveyen authored
241 ptd->downstream_assigns = 0;
ac7b45a @steveyen proxy_td_timeout started
steveyen authored
242 ptd->timeout_tv.tv_sec = 0;
243 ptd->timeout_tv.tv_usec = 0;
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
244 ptd->stats.stats.num_upstream = 0;
245 ptd->stats.stats.num_downstream_conn = 0;
b7a3357 @steveyen cproxy_reset_stats
steveyen authored
246
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
247 cproxy_reset_stats_td(&ptd->stats);
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
248
249 mcache_init(&ptd->key_stats, true,
250 &mcache_key_stats_funcs, false);
cead585 @steveyen key_stats_matcher doesn't have to be multithread safe
steveyen authored
251 matcher_init(&ptd->key_stats_matcher, false);
252 matcher_init(&ptd->key_stats_unmatcher, false);
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
253
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
254 if (behavior_pool->base.key_stats_max > 0 &&
255 behavior_pool->base.key_stats_lifespan > 0) {
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
256 mcache_start(&ptd->key_stats,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
257 behavior_pool->base.key_stats_max);
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
258
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
259 if (strlen(behavior_pool->base.key_stats_spec) > 0) {
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
260 matcher_start(&ptd->key_stats_matcher,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
261 behavior_pool->base.key_stats_spec);
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
262 }
263
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
264 if (strlen(behavior_pool->base.key_stats_unspec) > 0) {
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
265 matcher_start(&ptd->key_stats_unmatcher,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
266 behavior_pool->base.key_stats_unspec);
44ffe47 @steveyen key_stats moved to proxy thread data level for less locking
steveyen authored
267 }
268 }
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
269 }
f7e9500 @steveyen added work_queue to proxy_ptd
steveyen authored
270
2571b05 @steveyen moved work_queue into thread.c for proper, early initialization
steveyen authored
271 return p;
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
272 }
f7e9500 @steveyen added work_queue to proxy_ptd
steveyen authored
273
14c6d18 @steveyen compiles with memagent
steveyen authored
274 free(p->name);
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
275 free(p->config);
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
276 free(p->behavior_pool.arr);
005a5e1 @steveyen added sasl_mech/auth to proxy behavior, which is now more inheritable
steveyen authored
277 free(p->thread_data);
45cb61e @steveyen Turned behaviors into an array.
steveyen authored
278 free(p);
7e76b07 @steveyen cproxy_create and cproxy_create_downstream functions
steveyen authored
279 }
f7e9500 @steveyen added work_queue to proxy_ptd
steveyen authored
280
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
281 return NULL;
c6fa4d0 @steveyen cproxy_start function
steveyen authored
282 }
283
24042d2 @steveyen moved protocol handling stuff into cproxy_protocol.c
steveyen authored
284 /* Must be called on the main listener thread.
285 */
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
286 int cproxy_listen(proxy *p) {
c6fa4d0 @steveyen cproxy_start function
steveyen authored
287 assert(p != NULL);
6259111 @steveyen more proxy stats
steveyen authored
288 assert(is_listen_thread());
c6fa4d0 @steveyen cproxy_start function
steveyen authored
289
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
290 if (settings.verbose > 1) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
291 moxi_log_write("cproxy_listen on port %d, downstream %s\n",
23d3e54 @steveyen cproxy_init_conn called no matter what host
steveyen authored
292 p->port, p->config);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
293 }
85215f6 @steveyen testing output of cproxy_add_downstream
steveyen authored
294
de57975 @steveyen more comments
steveyen authored
295 // Idempotent, remembers if it already created listening socket(s).
296 //
6259111 @steveyen more proxy stats
steveyen authored
297 if (p->listening == 0) {
9aa776b @steveyen handle -B auto|ascii|binary cmd-line flag
steveyen authored
298 enum protocol listen_protocol = negotiating_proxy_prot;
299
300 if (IS_ASCII(settings.binding_protocol)) {
301 listen_protocol = proxy_upstream_ascii_prot;
302 }
303 if (IS_BINARY(settings.binding_protocol)) {
304 listen_protocol = proxy_upstream_binary_prot;
305 }
306
307 int listening = cproxy_listen_port(p->port, listen_protocol,
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
308 tcp_transport,
309 p,
310 &cproxy_listen_funcs);
311 if (listening > 0) {
312 p->listening += listening;
6259111 @steveyen more proxy stats
steveyen authored
313 } else {
314 p->listening_failed++;
6a6386c @steveyen bug 1813 - moxi exits if port is taken already
steveyen authored
315
04d6311 @steveyen bug 2576 - relevant err msg when bad uds socket
steveyen authored
316 if (settings.enable_mcmux_mode && settings.socketpath) {
317 #ifdef HAVE_SYS_UN_H
318 moxi_log_write("error: could not access UNIX socket: %s\n",
319 settings.socketpath);
320 if (ml->log_mode != ERRORLOG_STDERR) {
321 fprintf(stderr, "error: could not access UNIX socket: %s\n",
322 settings.socketpath);
323 }
324 exit(EXIT_FAILURE);
325 #endif
326 }
327
10cd773 @steveyen bug 1958 - using stderr if moxi exit()'s
steveyen authored
328 moxi_log_write("ERROR: could not listen on port %d. "
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
329 "Please use -Z port_listen=PORT_NUM "
330 "to specify a different port number.\n", p->port);
10cd773 @steveyen bug 1958 - using stderr if moxi exit()'s
steveyen authored
331 if (ml->log_mode != ERRORLOG_STDERR) {
332 fprintf(stderr, "ERROR: could not listen on port %d. "
333 "Please use -Z port_listen=PORT_NUM "
334 "to specify a different port number.\n", p->port);
335 }
336 exit(EXIT_FAILURE);
23d3e54 @steveyen cproxy_init_conn called no matter what host
steveyen authored
337 }
c6fa4d0 @steveyen cproxy_start function
steveyen authored
338 }
23d3e54 @steveyen cproxy_init_conn called no matter what host
steveyen authored
339
340 return p->listening;
c6fa4d0 @steveyen cproxy_start function
steveyen authored
341 }
342
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
343 int cproxy_listen_port(int port,
344 enum protocol protocol,
345 enum network_transport transport,
346 void *conn_extra,
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
347 conn_funcs *funcs) {
1b40490 @mtaneja fix support for unix domain sockets
mtaneja authored
348 assert(port > 0 || settings.socketpath != NULL);
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
349 assert(conn_extra);
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
350 assert(funcs);
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
351 assert(is_listen_thread());
352
353 int listening = 0;
354 conn *listen_conn_orig = listen_conn;
355
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
356 conn *x = listen_conn_orig;
357 while (x != NULL) {
358 if (x->extra != NULL &&
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
359 x->funcs == funcs) {
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
360 struct in_addr in = {0};
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
361 struct sockaddr_in s_in = {.sin_family = 0};
362 socklen_t sin_len = sizeof(s_in);
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
363
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
364 if (getsockname(x->sfd, (struct sockaddr *) &s_in, &sin_len) == 0) {
365 in.s_addr = s_in.sin_addr.s_addr;
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
366
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
367 int x_port = ntohs(s_in.sin_port);
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
368 if (x_port == port) {
7279bd7 @steveyen more debug logging
steveyen authored
369 if (settings.verbose > 1) {
370 moxi_log_write(
371 "<%d cproxy listening reusing listener on port %d\n",
372 x->sfd, port);
373 }
374
1042508 @steveyen cproxy_listen_port() checks if it's already listening on a port
steveyen authored
375 listening++;
376 }
377 }
378 }
379
380 x = x->next;
381 }
382
383 if (listening > 0) {
384 // If we're already listening on the required port, then
385 // we don't need to start a new server_socket(). This happens
386 // in the multi-bucket case with binary protocol buckets.
387 // There will be multiple proxy struct's (one per bucket), but
388 // only one proxy struct will actually be pointed at by a
389 // listening conn->extra (usually 11211).
390 //
391 // TODO: Add a refcount to handle shutdown properly?
392 //
393 return listening;
394 }
1b40490 @mtaneja fix support for unix domain sockets
mtaneja authored
395 #ifdef HAVE_SYS_UN_H
396 if (settings.socketpath ?
397 (server_socket_unix(settings.socketpath, settings.access) == 0) :
398 (server_socket(port, transport, NULL) == 0)) {
399 #else
48eb885 @dustin Merged in 1.4.1
dustin authored
400 if (server_socket(port, transport, NULL) == 0) {
1b40490 @mtaneja fix support for unix domain sockets
mtaneja authored
401 #endif
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
402 assert(listen_conn != NULL);
403
404 // The listen_conn global list is changed by server_socket(),
405 // which adds a new listening conn on port for each bindable
406 // host address.
407 //
408 // For example, after the call to server_socket(), there
409 // might be two new listening conn's -- one for localhost,
410 // another for 127.0.0.1.
411 //
412 conn *c = listen_conn;
413 while (c != NULL &&
414 c != listen_conn_orig) {
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
415 if (settings.verbose > 1) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
416 moxi_log_write(
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
417 "<%d cproxy listening on port %d\n",
418 c->sfd, port);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
419 }
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
420
421 listening++;
422
423 // TODO: Listening conn's never seem to close,
424 // but need to handle cleanup if they do,
425 // such as if we handle graceful shutdown one day.
426 //
427 c->extra = conn_extra;
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
428 c->funcs = funcs;
48eb885 @dustin Merged in 1.4.1
dustin authored
429 c->protocol = protocol;
ff10326 @steveyen refactored out cproxy_listen_port() into separate func
steveyen authored
430 c = c->next;
431 }
432 }
433
434 return listening;
435 }
436
e146b0e @steveyen some cproxy stats ideas
steveyen authored
437 /* Finds the proxy_td associated with a worker thread.
438 */
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
439 proxy_td *cproxy_find_thread_data(proxy *p, pthread_t thread_id) {
6ab3a40 @steveyen more asserts
steveyen authored
440 if (p != NULL) {
441 int i = thread_index(thread_id);
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
442
6ab3a40 @steveyen more asserts
steveyen authored
443 // 0 is the main listen thread, not a worker thread.
444 assert(i > 0);
445 assert(i < p->thread_data_num);
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
446
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
447 if (i > 0 && i < p->thread_data_num) {
6ab3a40 @steveyen more asserts
steveyen authored
448 return &p->thread_data[i];
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
449 }
6ab3a40 @steveyen more asserts
steveyen authored
450 }
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
451
452 return NULL;
453 }
454
7aef30f @steveyen MB-3113 - allow conn_init() callbacks to return an error
steveyen authored
455 bool cproxy_init_upstream_conn(conn *c) {
6ab3a40 @steveyen more asserts
steveyen authored
456 assert(c != NULL);
e886a14 @steveyen Cleanup and upstream/downstream conn init funcs only.
steveyen authored
457
b55b2ae @steveyen remembering proxy_td during cproxy_init_upstream_conn
steveyen authored
458 // We're called once per client/upstream conn early in its
e146b0e @steveyen some cproxy stats ideas
steveyen authored
459 // lifecycle, on the worker thread, so it's a good place
460 // to record the proxy_td into the conn->extra.
b55b2ae @steveyen remembering proxy_td during cproxy_init_upstream_conn
steveyen authored
461 //
54fe028 @steveyen assert, and better conflate_register descript string
steveyen authored
462 assert(!is_listen_thread());
463
e886a14 @steveyen Cleanup and upstream/downstream conn init funcs only.
steveyen authored
464 proxy *p = c->extra;
6ab3a40 @steveyen more asserts
steveyen authored
465 assert(p != NULL);
c25d4e6 @steveyen MB-3113 - close new upstream conns when there are no buckets
steveyen authored
466 assert(p->main != NULL);
467
468 int n = cproxy_num_active_proxies(p->main);
469 if (n <= 0) {
470 if (settings.verbose > 2) {
471 moxi_log_write("<%d disallowing upstream conn due to no buckets\n",
472 c->sfd);
473 }
474
475 return false;
476 }
6ab3a40 @steveyen more asserts
steveyen authored
477
478 proxy_td *ptd = cproxy_find_thread_data(p, pthread_self());
479 assert(ptd != NULL);
489fba8 @steveyen thread_index() to find the LIBEVENT_THREAD array index for a thread.
steveyen authored
480
1e0192d @steveyen bug 1998 - handle missing default bucket correctly
steveyen authored
481 // Reassign the client/upstream conn to a different bucket
482 // if the default_bucket_name isn't the special FIRST_BUCKET
483 // value.
484 //
485 char *default_name = ptd->behavior_pool.base.default_bucket_name;
486 if (strcmp(default_name, FIRST_BUCKET) != 0) {
487 if (settings.verbose > 2) {
488 moxi_log_write("<%d assigning to default bucket: %s\n",
489 c->sfd, default_name);
490 }
491
492 proxy *default_proxy =
493 cproxy_find_proxy_by_auth(p->main, default_name, "");
494
495 // If the ostensible default bucket is missing (possibly deleted),
496 // assign the client/upstream conn to the NULL BUCKET.
497 //
498 if (default_proxy == NULL) {
499 default_proxy =
500 cproxy_find_proxy_by_auth(p->main, NULL_BUCKET, "");
501
502 if (settings.verbose > 2) {
503 moxi_log_write("<%d assigning to null bucket, "
504 "default bucket missing: %s\n",
505 c->sfd, default_name);
506 }
507 }
508
509 if (default_proxy != NULL) {
510 proxy_td *default_ptd =
511 cproxy_find_thread_data(default_proxy, pthread_self());
512 if (default_ptd != NULL) {
513 ptd = default_ptd;
514 }
515 } else {
516 if (settings.verbose > 2) {
517 moxi_log_write("<%d assigning to first bucket, "
518 "missing default/null bucket: %s\n",
519 c->sfd, default_name);
520 }
521 }
522 } else {
523 if (settings.verbose > 2) {
524 moxi_log_write("<%d assigning to first bucket\n", c->sfd);
525 }
526 }
527
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
528 ptd->stats.stats.num_upstream++;
529 ptd->stats.stats.tot_upstream++;
513ec65 @steveyen added proxy_stats struct
steveyen authored
530
6ab3a40 @steveyen more asserts
steveyen authored
531 c->extra = ptd;
b1880bd @steveyen split out cproxy_listen_funcs into separate array
steveyen authored
532 c->funcs = &cproxy_upstream_funcs;
7aef30f @steveyen MB-3113 - allow conn_init() callbacks to return an error
steveyen authored
533
534 return true;
e886a14 @steveyen Cleanup and upstream/downstream conn init funcs only.
steveyen authored
535 }
536
7aef30f @steveyen MB-3113 - allow conn_init() callbacks to return an error
steveyen authored
537 bool cproxy_init_downstream_conn(conn *c) {
117e858 @steveyen downstream_conn extra is a downstream struct
steveyen authored
538 downstream *d = c->extra;
6259111 @steveyen more proxy stats
steveyen authored
539 assert(d != NULL);
540
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
541 d->ptd->stats.stats.num_downstream_conn++;
542 d->ptd->stats.stats.tot_downstream_conn++;
7aef30f @steveyen MB-3113 - allow conn_init() callbacks to return an error
steveyen authored
543
544 return true;
e886a14 @steveyen Cleanup and upstream/downstream conn init funcs only.
steveyen authored
545 }
546
71ae015 @steveyen renamed close funcs to sound more like callbacks
steveyen authored
547 void cproxy_on_close_upstream_conn(conn *c) {
f2a9f9a @steveyen cproxy_close_upstream/downstream_conn
steveyen authored
548 assert(c != NULL);
549
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
550 if (settings.verbose > 2) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
551 moxi_log_write("<%d cproxy_on_close_upstream_conn\n", c->sfd);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
552 }
f2a9f9a @steveyen cproxy_close_upstream/downstream_conn
steveyen authored
553
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
554 proxy_td *ptd = c->extra;
555 assert(ptd != NULL);
f2a9f9a @steveyen cproxy_close_upstream/downstream_conn
steveyen authored
556 c->extra = NULL;
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
557
72ed961 @steveyen bug 2015 - more warnings around signed/unsigned
steveyen authored
558 if (ptd->stats.stats.num_upstream > 0) {
559 ptd->stats.stats.num_upstream--;
560 }
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
561
438fe4e @steveyen comments
steveyen authored
562 // Delink from any reserved downstream.
563 //
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
564 for (downstream *d = ptd->downstream_reserved; d != NULL; d = d->next) {
ac4b3ee @steveyen cproxy_on_close_upstream cleans up multiget hash table
steveyen authored
565 bool found = false;
566
4d41fa1 @steveyen more reuse with conn_list_remove and fixed proxy_td_timeout
steveyen authored
567 d->upstream_conn = conn_list_remove(d->upstream_conn, NULL,
568 c, &found);
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
569 if (d->upstream_conn == NULL) {
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
570 d->upstream_suffix = NULL;
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
571 d->upstream_suffix_len = 0;
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
572 d->upstream_status = PROTOCOL_BINARY_RESPONSE_SUCCESS;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
573 d->upstream_retry = 0;
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
574 d->target_host_ident = NULL;
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
575
438fe4e @steveyen comments
steveyen authored
576 // Don't need to do anything else, as we'll now just
577 // read and drop any remaining inflight downstream replies.
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
578 // Eventually, the downstream will be released.
579 }
ac4b3ee @steveyen cproxy_on_close_upstream cleans up multiget hash table
steveyen authored
580
581 // If the downstream was reserved for this upstream conn,
582 // also clear the upstream from any multiget de-duplication
583 // tracking structures.
584 //
782c0f6 @steveyen todo comment on upstream closing at wrong moment
steveyen authored
585 if (found) {
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
586 if (d->multiget != NULL) {
ea4d064 @dustin Replaced glib dependency with a custom hash table.
dustin authored
587 genhash_iter(d->multiget, multiget_remove_upstream, c);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
588 }
782c0f6 @steveyen todo comment on upstream closing at wrong moment
steveyen authored
589
e0325b9 @steveyen close downstream when upstream closes in special mwrite case
steveyen authored
590 // The downstream conn's might have iov's that
591 // point to the upstream conn's buffers. Also, the
592 // downstream conn might be in all sorts of states
593 // (conn_read, write, mwrite, pause), and we want
594 // to be careful about the downstream channel being
595 // half written.
596 //
597 // The safest, but inefficient, thing to do then is
598 // to close any conn_mwrite downstream conns.
599 //
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
600 ptd->stats.stats.tot_downstream_close_on_upstream_close++;
90fdea8 @steveyen tot_downstream_close_on_upstream_close
steveyen authored
601
abef531 @steveyen first pass at removing direct libmemcached API calls
steveyen authored
602 int n = mcs_server_count(&d->mst);
e0325b9 @steveyen close downstream when upstream closes in special mwrite case
steveyen authored
603
604 for (int i = 0; i < n; i++) {
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
605 conn *downstream_conn = d->downstream_conns[i];
606 if (downstream_conn != NULL &&
8a09afd @steveyen NULL_CONN sentinel when connect() fails
steveyen authored
607 downstream_conn != NULL_CONN &&
e1ae2ef @alk fixes tons of warnings produced on GNU/Linux
alk authored
608 downstream_conn->state == conn_mwrite) {
609 downstream_conn->msgcurr = 0;
610 downstream_conn->msgused = 0;
611 downstream_conn->iovused = 0;
612
613 cproxy_close_conn(downstream_conn);
e0325b9 @steveyen close downstream when upstream closes in special mwrite case
steveyen authored
614 }
615 }
ac4b3ee @steveyen cproxy_on_close_upstream cleans up multiget hash table
steveyen authored
616 }
0f73218 @steveyen cproxy_on_close_upstream_conn() implemented
steveyen authored
617 }
618
ac4b3ee @steveyen cproxy_on_close_upstream cleans up multiget hash table
steveyen authored
619 // Delink from wait queue.
438fe4e @steveyen comments
steveyen authored
620 //
4d41fa1 @steveyen more reuse with conn_list_remove and fixed proxy_td_timeout
steveyen authored
621 ptd->waiting_any_downstream_head =
622 conn_list_remove(ptd->waiting_any_downstream_head,
623 &ptd->waiting_any_downstream_tail,
624 c, NULL);
f2a9f9a @steveyen cproxy_close_upstream/downstream_conn
steveyen authored
625 }
626
204bfca @steveyen cproxy_on_connect_downstream_conn hooked up
steveyen authored
627 int delink_from_downstream_conns(conn *c) {
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
628 downstream *d = c->extra;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
629 if (d == NULL) {
375f35e @steveyen MB-3099 - revert code from f763c6ae9f that stops cmd forwarding
steveyen authored
630 if (settings.verbose > 2) {
631 moxi_log_write("%d: delink_from_downstream_conn no-op\n",
632 c->sfd);
633 }
634
204bfca @steveyen cproxy_on_connect_downstream_conn hooked up
steveyen authored
635 return -1;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
636 }
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
637
abef531 @steveyen first pass at removing direct libmemcached API calls
steveyen authored
638 int n = mcs_server_count(&d->mst);
1021a58 @steveyen default downstream_retry is 1
steveyen authored
639 int k = -1; // Index of conn.
cd880a9 @steveyen Calling cproxy_prep_conn_for_write.
steveyen authored
640
c4c1f87 @steveyen implemented cproxy_on_close_downstream_conn
steveyen authored
641 for (int i = 0; i < n; i++) {
642 if (d->downstream_conns[i] == c) {
643 d->downstream_conns[i] = NULL;
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
644
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
645 if (settings.verbose > 2) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
646 moxi_log_write(
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
647 "<%d cproxy_on_close_downstream_conn quit_server\n",
648 c->sfd);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
649 }
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
650
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
651 d->ptd->stats.stats.tot_downstream_quit_server++;
6259111 @steveyen more proxy stats
steveyen authored
652
139bef4 @steveyen mcs_server_st_FIELD accessor macros for more opaque API's
steveyen authored
653 mcs_server_st_quit(mcs_server_index(&d->mst, i), 1);
654 assert(mcs_server_st_fd(mcs_server_index(&d->mst, i)) == -1);
1021a58 @steveyen default downstream_retry is 1
steveyen authored
655
656 k = i;
c4c1f87 @steveyen implemented cproxy_on_close_downstream_conn
steveyen authored
657 }
658 }
659
204bfca @steveyen cproxy_on_connect_downstream_conn hooked up
steveyen authored
660 return k;
661 }
662
663 void cproxy_on_close_downstream_conn(conn *c) {
664 assert(c != NULL);
665 assert(c->sfd >= 0);
666 assert(c->state == conn_closing);
667
668 if (settings.verbose > 2) {
669 moxi_log_write("<%d cproxy_on_close_downstream_conn\n", c->sfd);
670 }
671
672 downstream *d = c->extra;
673
674 // Might have been set to NULL during cproxy_free_downstream().
675 // Or, when a downstream conn is in the thread-based free pool, it
676 // is not associated with any particular downstream.
677 //
678 if (d == NULL) {
679 // TODO: See if we need to remove the downstream conn from the
680 // thread-based free pool. This shouldn't happen, but we
681 // should then figure out how to put an assert() here.
682 //
683 return;
684 }
685
686 int k = delink_from_downstream_conns(c);
687
8d7fd65 @steveyen bug MB-2660 - downstream_conn_max fix on closed conns
steveyen authored
688 c->extra = NULL;
689
690 if (c->thread != NULL &&
691 c->host_ident != NULL) {
692 zstored_error_count(c->thread, c->host_ident, true);
693 }
694
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
695 proxy_td *ptd = d->ptd;
696 assert(ptd);
697
72ed961 @steveyen bug 2015 - more warnings around signed/unsigned
steveyen authored
698 if (ptd->stats.stats.num_downstream_conn > 0) {
699 ptd->stats.stats.num_downstream_conn--;
700 }
6259111 @steveyen more proxy stats
steveyen authored
701
f763c6a @steveyen MB-3076 - broadcast commands have correct responses
steveyen authored
702 if (k < 0) {
703 // If this downstream conn wasn't linked into the
704 // downstream, it was delinked already during connect error
fa8a2e3 @steveyen MB-3129 - handle downstream_timeout/conn_queue_timeout cleaner
steveyen authored
705 // handling (where its slot was set to NULL_CONN already),
706 // or during downstream_timeout/conn_queue_timeout.
f763c6a @steveyen MB-3076 - broadcast commands have correct responses
steveyen authored
707 //
375f35e @steveyen MB-3099 - revert code from f763c6ae9f that stops cmd forwarding
steveyen authored
708 if (settings.verbose > 2) {
709 moxi_log_write("%d: skipping release dc in on_close_dc\n",
710 c->sfd);
711 }
712
f763c6a @steveyen MB-3076 - broadcast commands have correct responses
steveyen authored
713 return;
714 }
715
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
716 conn *uc_retry = NULL;
717
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
718 if (d->upstream_conn != NULL &&
d9160dc @steveyen generate upstream error when last downstream conn closes
steveyen authored
719 d->downstream_used == 1) {
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
720 // TODO: Revisit downstream close error handling.
d9160dc @steveyen generate upstream error when last downstream conn closes
steveyen authored
721 // Should we propagate error when...
722 // - any downstream conn closes?
723 // - all downstream conns closes?
2feec8d @steveyen cleanup comments
steveyen authored
724 // - last downstream conn closes? Current behavior.
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
725 //
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
726 if (d->upstream_suffix == NULL) {
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
727 if (settings.verbose > 2) {
728 moxi_log_write("<%d proxy downstream closed, upstream %d (%x)\n",
729 c->sfd,
730 d->upstream_conn->sfd,
731 d->upstream_conn->protocol);
732 }
733
734 if (IS_ASCII(d->upstream_conn->protocol)) {
735 d->upstream_suffix = "SERVER_ERROR proxy downstream closed\r\n";
d4879b6 @steveyen MB-3849 - SERVER_ERROR proxy downstream closed $HOST_IDENT
steveyen authored
736
737 if (c->host_ident != NULL) {
738 char *s = add_conn_suffix(d->upstream_conn);
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
739 if (s != NULL) {
740 snprintf(s, SUFFIX_SIZE - 1,
741 "SERVER_ERROR proxy downstream closed %s\r\n",
742 c->host_ident);
743 s[SUFFIX_SIZE - 1] = '\0';
744 d->upstream_suffix = s;
745
746 s = strchr(s, ':'); // Clip to avoid sending user/pswd.
747 if (s != NULL) {
36fe280 @steveyen MB-3856 - SERVER_ERROR proxy downstream timeout $HOST
steveyen authored
748 *s++ = '\r';
749 *s++ = '\n';
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
750 *s = '\0';
751 }
752 }
d4879b6 @steveyen MB-3849 - SERVER_ERROR proxy downstream closed $HOST_IDENT
steveyen authored
753 }
754
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
755 d->upstream_suffix_len = 0;
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
756 } else {
757 d->upstream_status = PROTOCOL_BINARY_RESPONSE_EINTERNAL;
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
758 }
759
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
760 d->upstream_retry = 0;
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
761 d->target_host_ident = NULL;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
762 }
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
763
2feec8d @steveyen cleanup comments
steveyen authored
764 // We sometimes see that drive_machine/transmit will not see
765 // a closed connection error during conn_mwrite, possibly
abe1a8c @steveyen comments about retrying downstream requests
steveyen authored
766 // due to non-blocking sockets. Because of this, drive_machine
767 // thinks it has a successful downstream request send and
768 // moves the state forward trying to read a response from
769 // the downstream conn (conn_new_cmd, conn_read, etc), and
770 // only then do we finally see the conn close situation,
960f5e4 @steveyen comments
steveyen authored
771 // ending up here. That is, drive_machine only
772 // seems to move to conn_closing from conn_read.
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
773 //
1021a58 @steveyen default downstream_retry is 1
steveyen authored
774 // If we haven't received any reply yet, we retry based
775 // on our cmd_retries counter.
2feec8d @steveyen cleanup comments
steveyen authored
776 //
777 // TODO: Reconsider retry behavior, is it right in all situations?
778 //
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
779 if (c->rcurr != NULL &&
780 c->rbytes == 0 &&
781 d->downstream_used_start == d->downstream_used &&
c3fd319 @steveyen added cmd_retries to conn
steveyen authored
782 d->downstream_used_start == 1 &&
a4da9e8 @steveyen tighter conditions on when to retry request
steveyen authored
783 d->upstream_conn->next == NULL &&
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
784 d->behaviors_arr != NULL) {
1021a58 @steveyen default downstream_retry is 1
steveyen authored
785 if (k >= 0 && k < d->behaviors_num) {
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
786 int retry_max = d->behaviors_arr[k].downstream_retry;
c3efc27 @steveyen configurable retries max, and clock resolution
steveyen authored
787 if (d->upstream_conn->cmd_retries < retry_max) {
788 d->upstream_conn->cmd_retries++;
789 uc_retry = d->upstream_conn;
790 d->upstream_suffix = NULL;
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
791 d->upstream_suffix_len = 0;
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
792 d->upstream_status = PROTOCOL_BINARY_RESPONSE_SUCCESS;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
793 d->upstream_retry = 0;
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
794 d->target_host_ident = NULL;
c3efc27 @steveyen configurable retries max, and clock resolution
steveyen authored
795 }
796 }
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
797 }
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
798
799 if (uc_retry == NULL &&
800 d->upstream_suffix == NULL &&
801 IS_BINARY(d->upstream_conn->protocol)) {
802 protocol_binary_response_header *rh =
803 cproxy_make_bin_error(d->upstream_conn,
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
804 PROTOCOL_BINARY_RESPONSE_EINTERNAL);
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
805 if (rh != NULL) {
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
806 d->upstream_suffix = (char *) rh;
57a5349 @steveyen MB-3389 - b2b not-my-vbucket handling
steveyen authored
807 d->upstream_suffix_len = sizeof(protocol_binary_response_header);
808 } else {
809 d->ptd->stats.stats.err_oom++;
810 cproxy_close_conn(d->upstream_conn);
811 }
812 }
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
813 }
843161b @steveyen No more hang when downstream goes away.
steveyen authored
814
58e27ff @steveyen comment on decrement thinking
steveyen authored
815 // Are we over-decrementing here, and in handling conn_pause?
816 //
817 // Case 1: we're in conn_pause, and socket is closed concurrently.
818 // We unpause due to reserve, we move to conn_write/conn_mwrite,
819 // fail and move to conn_closing. So, no over-decrement.
820 //
821 // Case 2: we're waiting for a downstream response in conn_new_cmd,
822 // and socket is closed concurrently. State goes to conn_closing,
823 // so, no over-decrement.
824 //
825 // Case 3: we've finished processing downstream response (in
826 // conn_parse_cmd or conn_nread), and the downstream socket
827 // is closed concurrently. We then move to conn_pause,
828 // and same as Case 1.
829 //
26de491 @steveyen releasing downstream conn during on_close handling
steveyen authored
830 cproxy_release_downstream_conn(d, c);
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
831
2feec8d @steveyen cleanup comments
steveyen authored
832 // Setup a retry after unwinding the call stack.
833 // We use the work_queue, because our caller, conn_close(),
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
834 // is likely to blow away our fd if we try to reconnect
835 // right now.
836 //
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
837 if (uc_retry != NULL) {
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
838 if (settings.verbose > 2) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
839 moxi_log_write("%d cproxy retrying\n", uc_retry->sfd);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
840 }
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
841
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
842 ptd->stats.stats.tot_retry++;
6259111 @steveyen more proxy stats
steveyen authored
843
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
844 assert(uc_retry->thread);
845 assert(uc_retry->thread->work_queue);
846
847 work_send(uc_retry->thread->work_queue,
848 upstream_retry, ptd, uc_retry);
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
849 }
f2a9f9a @steveyen cproxy_close_upstream/downstream_conn
steveyen authored
850 }
851
3b20de8 @steveyen upstream_retry needs to be called after stack unwind
steveyen authored
852 void upstream_retry(void *data0, void *data1) {
853 proxy_td *ptd = data0;
854 assert(ptd);
855
856 conn *uc = data1;
857 assert(uc);
858
859 cproxy_pause_upstream_for_downstream(ptd, uc);
860 }
861
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
862 void cproxy_add_downstream(proxy_td *ptd) {
9b492e7 @steveyen multithreaded cproxy with proxy_td struct
steveyen authored
863 assert(ptd != NULL);
b03809f @steveyen handle shutdown proxy by setting config to NULL
steveyen authored
864 assert(ptd->proxy != NULL);
c6fa4d0 @steveyen cproxy_start function
steveyen authored
865
72bd456 @steveyen downstream_max of 0 means unlimited
steveyen authored
866 if (ptd->downstream_max == 0 ||
867 ptd->downstream_num < ptd->downstream_max) {
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
868 if (settings.verbose > 2) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
869 moxi_log_write("cproxy_add_downstream %d %d\n",
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
870 ptd->downstream_num,
871 ptd->downstream_max);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
872 }
56f33cb @steveyen proxy_lock, and handling config change
steveyen authored
873
9ccc9bc @steveyen inheriting proxy behavior fixes
steveyen authored
874 // The config/behaviors will be NULL if the
d78329a @steveyen The downstream has own snapshot of behavior_str.
steveyen authored
875 // proxy is shutting down.
b5149ce @steveyen cproxy_on_new_serverlist no dependencies on memagent
steveyen authored
876 //
9ccc9bc @steveyen inheriting proxy behavior fixes
steveyen authored
877 if (ptd->config != NULL &&
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
878 ptd->behavior_pool.arr != NULL) {
44353a5 @steveyen refactor misc config slots into a proxy_behavior struct
steveyen authored
879 downstream *d =
9ccc9bc @steveyen inheriting proxy behavior fixes
steveyen authored
880 cproxy_create_downstream(ptd->config,
881 ptd->config_ver,
16be84f @steveyen proxy_behavior_pool struct
steveyen authored
882 &ptd->behavior_pool);
b5149ce @steveyen cproxy_on_new_serverlist no dependencies on memagent
steveyen authored
883 if (d != NULL) {
884 d->ptd = ptd;
885 ptd->downstream_tot++;
886 ptd->downstream_num++;
887 cproxy_release_downstream(d, true);
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
888 } else {
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
889 ptd->stats.stats.tot_downstream_create_failed++;
b5149ce @steveyen cproxy_on_new_serverlist no dependencies on memagent
steveyen authored
890 }
891 }
6259111 @steveyen more proxy stats
steveyen authored
892 } else {
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
893 ptd->stats.stats.tot_downstream_max_reached++;
052bcc3 @steveyen started cproxy.c/h
steveyen authored
894 }
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
895 }
896
897 downstream *cproxy_reserve_downstream(proxy_td *ptd) {
898 assert(ptd != NULL);
899
4b06ac6 @steveyen more splitting long lines
steveyen authored
900 // Loop in case we need to clear out downstreams
901 // that have outdated configs.
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
902 //
903 while (true) {
904 downstream *d;
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
905
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
906 d = ptd->downstream_released;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
907 if (d == NULL) {
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
908 cproxy_add_downstream(ptd);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
909 }
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
910
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
911 d = ptd->downstream_released;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
912 if (d == NULL) {
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
913 return NULL;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
914 }
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
915
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
916 ptd->downstream_released = d->next;
03d6ce6 @steveyen more asserts and cproxy_connect_downstream() getting closer.
steveyen authored
917
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
918 assert(d->upstream_conn == NULL);
919 assert(d->upstream_suffix == NULL);
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
920 assert(d->upstream_suffix_len == 0);
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
921 assert(d->upstream_status == PROTOCOL_BINARY_RESPONSE_SUCCESS);
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
922 assert(d->upstream_retry == 0);
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
923 assert(d->target_host_ident == NULL);
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
924 assert(d->downstream_used == 0);
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
925 assert(d->downstream_used_start == 0);
99075cc @steveyen added merger hashtable for stats
steveyen authored
926 assert(d->merger == NULL);
b994936 @steveyen started timeout fields
steveyen authored
927 assert(d->timeout_tv.tv_sec == 0);
928 assert(d->timeout_tv.tv_usec == 0);
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
929 assert(d->next_waiting == NULL);
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
930
931 d->upstream_conn = NULL;
932 d->upstream_suffix = NULL;
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
933 d->upstream_suffix_len = 0;
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
934 d->upstream_status = PROTOCOL_BINARY_RESPONSE_SUCCESS;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
935 d->upstream_retry = 0;
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
936 d->upstream_retries = 0;
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
937 d->target_host_ident = NULL;
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
938 d->usec_start = 0;
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
939 d->downstream_used = 0;
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
940 d->downstream_used_start = 0;
99075cc @steveyen added merger hashtable for stats
steveyen authored
941 d->merger = NULL;
b994936 @steveyen started timeout fields
steveyen authored
942 d->timeout_tv.tv_sec = 0;
943 d->timeout_tv.tv_usec = 0;
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
944 d->next_waiting = NULL;
03d6ce6 @steveyen more asserts and cproxy_connect_downstream() getting closer.
steveyen authored
945
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
946 if (cproxy_check_downstream_config(d)) {
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
947 ptd->downstream_reserved =
948 downstream_list_remove(ptd->downstream_reserved, d);
949 ptd->downstream_released =
950 downstream_list_remove(ptd->downstream_released, d);
951
fa8a2e3 @steveyen MB-3129 - handle downstream_timeout/conn_queue_timeout cleaner
steveyen authored
952 bool found = zstored_downstream_waiting_remove(d);
953 assert(!found);
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
954
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
955 d->next = ptd->downstream_reserved;
956 ptd->downstream_reserved = d;
957
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
958 ptd->stats.stats.tot_downstream_reserved++;
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
959
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
960 return d;
961 }
962
963 cproxy_free_downstream(d);
964 }
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
965 }
966
31821cf @steveyen cproxy_clear_timeout() helper func
steveyen authored
967 bool cproxy_clear_timeout(downstream *d) {
968 bool rv = false;
969
970 if (d->timeout_tv.tv_sec != 0 ||
971 d->timeout_tv.tv_usec != 0) {
972 evtimer_del(&d->timeout_event);
973 rv = true;
974 }
975
976 d->timeout_tv.tv_sec = 0;
977 d->timeout_tv.tv_usec = 0;
978
979 return rv;
980 }
981
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
982 bool cproxy_release_downstream(downstream *d, bool force) {
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
983 assert(d != NULL);
984 assert(d->ptd != NULL);
985
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
986 if (settings.verbose > 2) {
6f64e3e @steveyen downstream_conn->extra now set/cleared during acquire/release
steveyen authored
987 moxi_log_write("%d: release_downstream\n",
988 d->upstream_conn != NULL ?
989 d->upstream_conn->sfd : -1);
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
990 }
f2b6bf6 @steveyen lots of conn_pause refactor in prep for noreply
steveyen authored
991
2910f24 @steveyen bug 1512 - don't leak timeout_event registrations
steveyen authored
992 // Always release the timeout_event, even if we're going to retry,
993 // to avoid pegging CPU with leaked timeout_events.
994 //
31821cf @steveyen cproxy_clear_timeout() helper func
steveyen authored
995 cproxy_clear_timeout(d);
2910f24 @steveyen bug 1512 - don't leak timeout_event registrations
steveyen authored
996
d785d2d @steveyen b2b upstream & downstream for simple, non-quiet commands
steveyen authored
997 // If we need to retry the command, we do so here,
998 // keeping the same downstream that would otherwise
999 // be released.
1000 //
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1001 if (!force &&
0f3a435 @steveyen cproxy_forward assert(d->upstream_conn != NULL) cproxy.c, 1925
steveyen authored
1002 d->upstream_conn != NULL &&
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1003 d->upstream_retry > 0) {
1004 d->upstream_retry = 0;
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1005 d->upstream_retries++;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1006
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1007 // But, we can stop retrying if we've tried each server twice.
1008 //
f76dee5 @steveyen cproxy_max_retries() helper func
steveyen authored
1009 int max_retries = cproxy_max_retries(d);
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1010
1011 if (d->upstream_retries <= max_retries) {
1012 if (settings.verbose > 2) {
53c7269 @steveyen more stats around acquire/release
steveyen authored
1013 moxi_log_write("%d: release_downstream,"
1014 " instead retrying %d, %d <= %d, %d\n",
e5b8111 @steveyen notes on zstored-conn-pooling semantics for cproxy_connect_downstream()
steveyen authored
1015 d->upstream_conn->sfd,
53c7269 @steveyen more stats around acquire/release
steveyen authored
1016 d->upstream_retry,
1017 d->upstream_retries, max_retries,
1018 d->ptd->stats.stats.tot_retry);
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1019 }
1020
53c7269 @steveyen more stats around acquire/release
steveyen authored
1021 d->ptd->stats.stats.tot_retry++;
1022
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1023 if (cproxy_forward(d) == true) {
1024 return true;
1025 } else {
1026 d->ptd->stats.stats.tot_downstream_propagate_failed++;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1027
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
1028 propagate_error_msg(d, NULL, d->upstream_status);
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1029 }
1030 } else {
1031 if (settings.verbose > 2) {
53c7269 @steveyen more stats around acquire/release
steveyen authored
1032 moxi_log_write("%d: release_downstream,"
1033 " skipping retry %d, %d > %d\n",
e5b8111 @steveyen notes on zstored-conn-pooling semantics for cproxy_connect_downstream()
steveyen authored
1034 d->upstream_conn->sfd,
53c7269 @steveyen more stats around acquire/release
steveyen authored
1035 d->upstream_retry,
1036 d->upstream_retries, max_retries);
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1037 }
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1038 }
1039 }
1040
fd2c701 @steveyen zstored_perf / list for tracking waiting downstreams
steveyen authored
1041 // Record reserved_time histogram timings.
1042 //
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
1043 if (d->usec_start > 0) {
1044 uint64_t ux = usec_now() - d->usec_start;
1045
1046 d->ptd->stats.stats.tot_downstream_reserved_time += ux;
1047
29e719f @steveyen bug 1911 - tracking max downstream reserved time stat
steveyen authored
1048 if (d->ptd->stats.stats.max_downstream_reserved_time < ux) {
1049 d->ptd->stats.stats.max_downstream_reserved_time = ux;
1050 }
1051
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
1052 if (d->upstream_retries > 0) {
1053 d->ptd->stats.stats.tot_retry_time += ux;
9e23e48 @steveyen bug 1911 -- max_retry_time stats tracking
steveyen authored
1054
1055 if (d->ptd->stats.stats.max_retry_time < ux) {
1056 d->ptd->stats.stats.max_retry_time = ux;
1057 }
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
1058 }
0739827 @steveyen downstreaming timing histogram
steveyen authored
1059
1060 downstream_reserved_time_sample(&d->ptd->stats, ux);
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
1061 }
1062
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
1063 d->ptd->stats.stats.tot_downstream_released++;
fb1e2ca @steveyen cproxy_release/reserve_downstream()
steveyen authored
1064
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1065 // Delink upstream conns.
1066 //
1067 while (d->upstream_conn != NULL) {
89324b9 @steveyen stats merging
steveyen authored
1068 if (d->merger != NULL) {
b994936 @steveyen started timeout fields
steveyen authored
1069 // TODO: Allow merger callback to be func pointer.
1070 //
ea4d064 @dustin Replaced glib dependency with a custom hash table.
dustin authored
1071 genhash_iter(d->merger,
1072 protocol_stats_foreach_write,
1073 d->upstream_conn);
89324b9 @steveyen stats merging
steveyen authored
1074
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
1075 if (update_event(d->upstream_conn, EV_WRITE | EV_PERSIST)) {
1076 conn_set_state(d->upstream_conn, conn_mwrite);
1077 } else {
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
1078 d->ptd->stats.stats.err_oom++;
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
1079 cproxy_close_conn(d->upstream_conn);
1080 }
89324b9 @steveyen stats merging
steveyen authored
1081 }
1082
88005dc @steveyen MB-3067 - suffix missing for broadcast commands on connect error
steveyen authored
1083 if (settings.verbose > 2) {
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
1084 moxi_log_write("%d: release_downstream upstream_suffix %s status %x\n",
88005dc @steveyen MB-3067 - suffix missing for broadcast commands on connect error
steveyen authored
1085 d->upstream_conn->sfd,
1086 d->upstream_suffix_len == 0 ?
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
1087 d->upstream_suffix : "(binary)",
1088 d->upstream_status);
88005dc @steveyen MB-3067 - suffix missing for broadcast commands on connect error
steveyen authored
1089 }
1090
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1091 if (d->upstream_suffix != NULL) {
1092 // Do a last write on the upstream. For example,
1093 // the upstream_suffix might be "END\r\n" or other
1094 // way to mark the end of a scatter-gather or
1095 // multiline response.
1096 //
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
1097 if (settings.verbose > 2) {
1098 if (d->upstream_suffix_len > 0) {
53c7269 @steveyen more stats around acquire/release
steveyen authored
1099 moxi_log_write("%d: release_downstream"
1100 " writing suffix binary: %d\n",
1101 d->upstream_conn->sfd,
1102 d->upstream_suffix_len);
b363a03 @steveyen binary header debug output is now zstored/log friendly
steveyen authored
1103
53c7269 @steveyen more stats around acquire/release
steveyen authored
1104 cproxy_dump_header(d->upstream_conn->sfd,
1105 d->upstream_suffix);
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
1106 } else {
53c7269 @steveyen more stats around acquire/release
steveyen authored
1107 moxi_log_write("%d: release_downstream"
1108 " writing suffix ascii: %s\n",
1109 d->upstream_conn->sfd,
1110 d->upstream_suffix);
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
1111 }
1112 }
1113
1114 int suffix_len = d->upstream_suffix_len;
1115 if (suffix_len == 0) {
1116 suffix_len = strlen(d->upstream_suffix);
1117 }
1118
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1119 if (add_iov(d->upstream_conn,
1120 d->upstream_suffix,
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
1121 suffix_len) == 0 &&
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1122 update_event(d->upstream_conn, EV_WRITE | EV_PERSIST)) {
1123 conn_set_state(d->upstream_conn, conn_mwrite);
1124 } else {
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
1125 d->ptd->stats.stats.err_oom++;
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1126 cproxy_close_conn(d->upstream_conn);
1127 }
1147c5c @steveyen Added upstream_suffix to allow final END to multi-get
steveyen authored
1128 }
7e747eb @steveyen more progress on multiget key dedpue
steveyen authored
1129
1130 conn *curr = d->upstream_conn;
1131 d->upstream_conn = d->upstream_conn->next;
1132 curr->next = NULL;
1147c5c @steveyen Added upstream_suffix to allow final END to multi-get
steveyen authored
1133 }
1134
99075cc @steveyen added merger hashtable for stats
steveyen authored
1135 // Free extra hash tables.
5f7e13c @steveyen free the multiget hash table when releasing the downstream
steveyen authored
1136 //
1137 if (d->multiget != NULL) {
ea4d064 @dustin Replaced glib dependency with a custom hash table.
dustin authored
1138 genhash_iter(d->multiget, multiget_foreach_free, d);
1139 genhash_free(d->multiget);
5f7e13c @steveyen free the multiget hash table when releasing the downstream
steveyen authored
1140 d->multiget = NULL;
1141 }
1142
99075cc @steveyen added merger hashtable for stats
steveyen authored
1143 if (d->merger != NULL) {
ea4d064 @dustin Replaced glib dependency with a custom hash table.
dustin authored
1144 genhash_iter(d->merger, protocol_stats_foreach_free, NULL);
1145 genhash_free(d->merger);
99075cc @steveyen added merger hashtable for stats
steveyen authored
1146 d->merger = NULL;
1147 }
1148
c9ce4a6 @steveyen Rewrote assign_downstream() in preparation for set.
steveyen authored
1149 d->upstream_conn = NULL;
1147c5c @steveyen Added upstream_suffix to allow final END to multi-get
steveyen authored
1150 d->upstream_suffix = NULL; // No free(), expecting a static string.
7f7f4a1 @steveyen bug 1497 - binary-2-binary broadcast command impl was wrong
steveyen authored
1151 d->upstream_suffix_len = 0;
5fa3a33 @steveyen MB-3479 - Use binary protocol EBUSY & EINTERNAL instead of ENOMEM
steveyen authored
1152 d->upstream_status = PROTOCOL_BINARY_RESPONSE_SUCCESS;
4aa49f5 @steveyen upstream_retry when multi-GET not-my-vbucket err
steveyen authored
1153 d->upstream_retry = 0;
18cb892 @steveyen bug 1429 - stop retrying after too many ascii-to-binary retries
steveyen authored
1154 d->upstream_retries = 0;
0745b38 @steveyen MB-3849 - SERVER_ERROR proxy write to downstream $HOST
steveyen authored
1155 d->target_host_ident = NULL;
6b4a7e7 @steveyen stats for usec spent with a reserved downstream or on retries
steveyen authored
1156 d->usec_start = 0;
2f87767 @steveyen multi-get works
steveyen authored
1157 d->downstream_used = 0;
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
1158 d->downstream_used_start = 0;
5f7e13c @steveyen free the multiget hash table when releasing the downstream
steveyen authored
1159 d->multiget = NULL;
99075cc @steveyen added merger hashtable for stats
steveyen authored
1160 d->merger = NULL;
a289704 @steveyen tracking list of downstream_reserved
steveyen authored
1161
08dc908 @steveyen CBSE-126 - clear links & timeouts before and after releasing conn
steveyen authored
1162 // TODO: Consider adding a downstream->prev backpointer
1163 // or doubly-linked list to save on this scan.
1164 //
1165 d->ptd->downstream_reserved =
1166 downstream_list_remove(d->ptd->downstream_reserved, d);
1167 d->ptd->downstream_released =
1168 downstream_list_remove(d->ptd->downstream_released, d);
1169
1170 bool found = zstored_downstream_waiting_remove(d);
1171 assert(!found);
1172
33c6f1d @steveyen handling EINPROGRESS result from mcs_connect()
steveyen authored
1173 int n = mcs_server_count(&d->mst);
1174
1175 for (int i = 0; i < n; i++) {
1176 conn *dc = d->downstream_conns[i];
8a09afd @steveyen NULL_CONN sentinel when connect() fails
steveyen authored
1177 d->downstream_conns[i] = NULL;
33c6f1d @steveyen handling EINPROGRESS result from mcs_connect()
steveyen authored
1178 if (dc != NULL) {
1179 zstored_release_downstream_conn(dc, false);
1180 }
1181 }
1182
cb602b1 @steveyen MB-4334 - clear downstream timeout before releasing
steveyen authored
1183 cproxy_clear_timeout(d); // For MB-4334.
1184
1185 assert(d->timeout_tv.tv_sec == 0);
1186 assert(d->timeout_tv.tv_usec == 0);
1187
56f33cb @steveyen proxy_lock, and handling config change
steveyen authored
1188 // If this downstream still has the same configuration as our top-level
1189 // proxy config, go back onto the available, released downstream list.
4f6634a @steveyen cproxy_release_downstream
steveyen authored
1190 //
56f33cb @steveyen proxy_lock, and handling config change
steveyen authored
1191 if (cproxy_check_downstream_config(d) || force) {
4f6634a @steveyen cproxy_release_downstream
steveyen authored
1192 d->next = d->ptd->downstream_released;
1193 d->ptd->downstream_released = d;
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1194
1195 return true;
4f6634a @steveyen cproxy_release_downstream
steveyen authored
1196 }
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1197
1198 cproxy_free_downstream(d);
1199
1200 return false;
1201 }
1202
1203 void cproxy_free_downstream(downstream *d) {
1204 assert(d != NULL);
b7fe3a2 @steveyen downstream_num decrement on free_downstream
steveyen authored
1205 assert(d->ptd != NULL);
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1206 assert(d->upstream_conn == NULL);
5f7e13c @steveyen free the multiget hash table when releasing the downstream
steveyen authored
1207 assert(d->multiget == NULL);
99075cc @steveyen added merger hashtable for stats
steveyen authored
1208 assert(d->merger == NULL);
b994936 @steveyen started timeout fields
steveyen authored
1209 assert(d->timeout_tv.tv_sec == 0);
1210 assert(d->timeout_tv.tv_usec == 0);
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1211
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
1212 if (settings.verbose > 2) {
6a48c21 @mtaneja Migrate to using moxi log
mtaneja authored
1213 moxi_log_write("cproxy_free_downstream\n");
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
1214 }
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1215
1de95aa @steveyen proxy_stats_cmd and proxy_stats_td
steveyen authored
1216 d->ptd->stats.stats.tot_downstream_freed++;
be29f30 @steveyen more stats and err handling around update_event
steveyen authored
1217
d35fcd6 @steveyen more uniformity on released/reserved list mgmt
steveyen authored
1218 d->ptd->downstream_reserved =
1219 downstream_list_remove(d->ptd->downstream_reserved, d);
1220 d->ptd->downstream_released =
1221 downstream_list_remove(d->ptd->downstream_released, d);
1222
fa8a2e3 @steveyen MB-3129 - handle downstream_timeout/conn_queue_timeout cleaner
steveyen authored
1223 bool found = zstored_downstream_waiting_remove(d);
1224 assert(!found);
38397ad @steveyen downstream_waiting_head/tail started
steveyen authored
1225
b7fe3a2 @steveyen downstream_num decrement on free_downstream
steveyen authored
1226 d->ptd->downstream_num--;
1227 assert(d->ptd->downstream_num >= 0);
1228
abef531 @steveyen first pass at removing direct libmemcached API calls
steveyen authored
1229 int n = mcs_server_count(&d->mst);
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
1230
8977cae @ingenthr fix core dump
ingenthr authored
1231 if (d->downstream_conns != NULL) {
1232 for (int i = 0; i < n; i++) {
8a09afd @steveyen NULL_CONN sentinel when connect() fails
steveyen authored
1233 if (d->downstream_conns[i] != NULL &&
1234 d->downstream_conns[i] != NULL_CONN) {
8977cae @ingenthr fix core dump
ingenthr authored
1235 d->downstream_conns[i]->extra = NULL;
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
1236 }
8977cae @ingenthr fix core dump
ingenthr authored
1237 }
1238 }
2164eb4 @steveyen reserving a downstream now checks for config match
steveyen authored
1239
1240 // This will close sockets, which will force associated conn's
1241 // to go to conn_closing state. Since we've already cleared
1242 // the conn->extra pointers, there's no extra release/free.
1243 //
abef531 @steveyen first pass at removing direct libmemcached API calls
steveyen authored
1244 mcs_free(&d->mst);
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1245
31821cf @steveyen cproxy_clear_timeout() helper func
steveyen authored
1246 cproxy_clear_timeout(d);
b994936 @steveyen started timeout fields
steveyen authored
1247
cf6d49a @steveyen coding style of if statements with braces
steveyen authored
1248 if (d->downstream_conns != NULL) {
eb0336f @steveyen cproxy_free_downstream and cproxy_release_downstream(takes force flag…
steveyen authored
1249 free(d->downstream_conns);