Adding gtest framework.
[awesomized/libmemcached] / libmemcached / behavior.c
1 /* LibMemcached
2 * Copyright (C) 2006-2009 Brian Aker
3 * All rights reserved.
4 *
5 * Use and distribution licensed under the BSD license. See
6 * the COPYING file in the parent directory for full text.
7 *
8 * Summary: Change the behavior of the memcached connection.
9 *
10 */
11
12 #include "common.h"
13 #include <time.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/tcp.h>
17
18 static bool set_flag(uint64_t data)
19 {
20 // Wordy :)
21 return data ? true : false;
22 }
23
24 /*
25 This function is used to modify the behavior of running client.
26
27 We quit all connections so we can reset the sockets.
28 */
29
30 memcached_return_t memcached_behavior_set(memcached_st *ptr,
31 const memcached_behavior_t flag,
32 uint64_t data)
33 {
34 switch (flag)
35 {
36 case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
37 ptr->number_of_replicas= (uint32_t)data;
38 break;
39 case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
40 ptr->io_msg_watermark= (uint32_t) data;
41 break;
42 case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
43 ptr->io_bytes_watermark= (uint32_t)data;
44 break;
45 case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
46 ptr->io_key_prefetch = (uint32_t)data;
47 break;
48 case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
49 ptr->snd_timeout= (int32_t)data;
50 break;
51 case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
52 ptr->rcv_timeout= (int32_t)data;
53 break;
54 case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
55 ptr->server_failure_limit= (uint32_t)data;
56 break;
57 case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
58 memcached_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
59 if (data)
60 {
61 ptr->flags.verify_key= false;
62 }
63 ptr->flags.binary_protocol= set_flag(data);
64 break;
65 case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
66 ptr->flags.support_cas= set_flag(data);
67 break;
68 case MEMCACHED_BEHAVIOR_NO_BLOCK:
69 ptr->flags.no_block= set_flag(data);
70 memcached_quit(ptr);
71 break;
72 case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
73 ptr->flags.buffer_requests= set_flag(data);
74 memcached_quit(ptr);
75 break;
76 case MEMCACHED_BEHAVIOR_USE_UDP:
77 if (memcached_server_count(ptr))
78 {
79 return MEMCACHED_FAILURE;
80 }
81 ptr->flags.use_udp= set_flag(data);
82 if (data)
83 {
84 ptr->flags.no_reply= set_flag(data);
85 }
86 break;
87 case MEMCACHED_BEHAVIOR_TCP_NODELAY:
88 ptr->flags.tcp_nodelay= set_flag(data);
89 memcached_quit(ptr);
90 break;
91 case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
92 ptr->flags.tcp_keepalive= set_flag(data);
93 memcached_quit(ptr);
94 break;
95 case MEMCACHED_BEHAVIOR_DISTRIBUTION:
96 return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
97 case MEMCACHED_BEHAVIOR_KETAMA:
98 {
99 if (data)
100 {
101 (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
102 (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
103 (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
104 }
105 else
106 {
107 (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_DEFAULT);
108 (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_DEFAULT);
109 (void)memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
110 }
111
112 break;
113 }
114 case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
115 {
116 (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
117 (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
118 ptr->flags.ketama_weighted= set_flag(data);
119 /**
120 @note We try to keep the same distribution going. This should be deprecated and rewritten.
121 */
122 return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
123 }
124 case MEMCACHED_BEHAVIOR_HASH:
125 return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
126 case MEMCACHED_BEHAVIOR_KETAMA_HASH:
127 return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
128 case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
129 ptr->flags.use_cache_lookups= set_flag(data);
130 memcached_quit(ptr);
131 break;
132 case MEMCACHED_BEHAVIOR_VERIFY_KEY:
133 if (ptr->flags.binary_protocol)
134 return MEMCACHED_FAILURE;
135 ptr->flags.verify_key= set_flag(data);
136 break;
137 case MEMCACHED_BEHAVIOR_SORT_HOSTS:
138 {
139 ptr->flags.use_sort_hosts= set_flag(data);
140 run_distribution(ptr);
141
142 break;
143 }
144 case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
145 ptr->poll_timeout= (int32_t)data;
146 break;
147 case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
148 ptr->connect_timeout= (int32_t)data;
149 break;
150 case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
151 ptr->retry_timeout= (int32_t)data;
152 break;
153 case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
154 ptr->send_size= (int32_t)data;
155 memcached_quit(ptr);
156 break;
157 case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
158 ptr->recv_size= (int32_t)data;
159 memcached_quit(ptr);
160 break;
161 case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
162 ptr->tcp_keepidle= (uint32_t)data;
163 memcached_quit(ptr);
164 break;
165 case MEMCACHED_BEHAVIOR_USER_DATA:
166 return MEMCACHED_FAILURE;
167 case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
168 ptr->flags.hash_with_prefix_key= set_flag(data);
169 break;
170 case MEMCACHED_BEHAVIOR_NOREPLY:
171 ptr->flags.no_reply= set_flag(data);
172 break;
173 case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
174 ptr->flags.auto_eject_hosts= set_flag(data);
175 break;
176 case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
177 srandom((uint32_t) time(NULL));
178 ptr->flags.randomize_replica_read= set_flag(data);
179 break;
180 case MEMCACHED_BEHAVIOR_CORK:
181 {
182 memcached_server_write_instance_st instance;
183 bool action= set_flag(data);
184
185 if (action == false)
186 {
187 ptr->flags.cork= set_flag(false);
188 return MEMCACHED_SUCCESS;
189 }
190
191 instance= memcached_server_instance_fetch(ptr, 0);
192 if (! instance)
193 return MEMCACHED_NO_SERVERS;
194
195
196 /* We just try the first host, and if it is down we return zero */
197 memcached_return_t rc;
198 rc= memcached_connect(instance);
199 if (rc != MEMCACHED_SUCCESS)
200 {
201 return rc;
202 }
203
204 /* Now we test! */
205 memcached_ternary_t enabled;
206 enabled= test_cork(instance, true);
207
208 switch (enabled)
209 {
210 case MEM_FALSE:
211 return ptr->cached_errno ? MEMCACHED_ERRNO : MEMCACHED_FAILURE ;
212 case MEM_TRUE:
213 {
214 enabled= test_cork(instance, false);
215
216 if (enabled == false) // Possible bug in OS?
217 {
218 memcached_quit_server(instance, false); // We should reset everything on this error.
219 return MEMCACHED_ERRNO; // Errno will be true because we will have already set it.
220 }
221 ptr->flags.cork= true;
222 ptr->flags.tcp_nodelay= true;
223 memcached_quit(ptr); // We go on and reset the connections.
224 }
225 break;
226 case MEM_NOT:
227 default:
228 return MEMCACHED_NOT_SUPPORTED;
229 }
230 }
231 break;
232 case MEMCACHED_BEHAVIOR_MAX:
233 default:
234 /* Shouldn't get here */
235 WATCHPOINT_ASSERT(0);
236 return MEMCACHED_FAILURE;
237 }
238
239 return MEMCACHED_SUCCESS;
240 }
241
242 bool _is_auto_eject_host(const memcached_st *ptr)
243 {
244 return ptr->flags.auto_eject_hosts;
245 }
246
247 uint64_t memcached_behavior_get(memcached_st *ptr,
248 const memcached_behavior_t flag)
249 {
250 switch (flag)
251 {
252 case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
253 return ptr->number_of_replicas;
254 case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
255 return ptr->io_msg_watermark;
256 case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
257 return ptr->io_bytes_watermark;
258 case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
259 return ptr->io_key_prefetch;
260 case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
261 return ptr->flags.binary_protocol;
262 case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
263 return ptr->flags.support_cas;
264 case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
265 return ptr->flags.use_cache_lookups;
266 case MEMCACHED_BEHAVIOR_NO_BLOCK:
267 return ptr->flags.no_block;
268 case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
269 return ptr->flags.buffer_requests;
270 case MEMCACHED_BEHAVIOR_USE_UDP:
271 return ptr->flags.use_udp;
272 case MEMCACHED_BEHAVIOR_TCP_NODELAY:
273 return ptr->flags.tcp_nodelay;
274 case MEMCACHED_BEHAVIOR_VERIFY_KEY:
275 return ptr->flags.verify_key;
276 case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
277 return ptr->flags.ketama_weighted;
278 case MEMCACHED_BEHAVIOR_DISTRIBUTION:
279 return ptr->distribution;
280 case MEMCACHED_BEHAVIOR_KETAMA:
281 return (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA) ? (uint64_t) 1 : 0;
282 case MEMCACHED_BEHAVIOR_HASH:
283 return hashkit_get_function(&ptr->hashkit);
284 case MEMCACHED_BEHAVIOR_KETAMA_HASH:
285 return hashkit_get_function(&ptr->distribution_hashkit);
286 case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
287 return ptr->server_failure_limit;
288 case MEMCACHED_BEHAVIOR_SORT_HOSTS:
289 return ptr->flags.use_sort_hosts;
290 case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
291 return (uint64_t)ptr->poll_timeout;
292 case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
293 return (uint64_t)ptr->connect_timeout;
294 case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
295 return (uint64_t)ptr->retry_timeout;
296 case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
297 return (uint64_t)ptr->snd_timeout;
298 case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
299 return (uint64_t)ptr->rcv_timeout;
300 case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
301 return (uint64_t)ptr->tcp_keepidle;
302 case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
303 {
304 int sock_size= 0;
305 socklen_t sock_length= sizeof(int);
306 memcached_server_write_instance_st instance;
307
308 if (ptr->send_size != -1) // If value is -1 then we are using the default
309 return (uint64_t) ptr->send_size;
310
311 instance= memcached_server_instance_fetch(ptr, 0);
312
313 if (instance) // If we have an instance we test, otherwise we just set and pray
314 {
315 /* REFACTOR */
316 /* We just try the first host, and if it is down we return zero */
317 if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
318 return 0;
319
320 if (getsockopt(instance->fd, SOL_SOCKET,
321 SO_SNDBUF, &sock_size, &sock_length))
322 return 0; /* Zero means error */
323 }
324
325 return (uint64_t) sock_size;
326 }
327 case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
328 {
329 int sock_size= 0;
330 socklen_t sock_length= sizeof(int);
331 memcached_server_write_instance_st instance;
332
333 if (ptr->recv_size != -1) // If value is -1 then we are using the default
334 return (uint64_t) ptr->recv_size;
335
336 instance= memcached_server_instance_fetch(ptr, 0);
337
338 /**
339 @note REFACTOR
340 */
341 if (instance)
342 {
343 /* We just try the first host, and if it is down we return zero */
344 if ((memcached_connect(instance)) != MEMCACHED_SUCCESS)
345 return 0;
346
347 if (getsockopt(instance->fd, SOL_SOCKET,
348 SO_RCVBUF, &sock_size, &sock_length))
349 return 0; /* Zero means error */
350
351 }
352
353 return (uint64_t) sock_size;
354 }
355 case MEMCACHED_BEHAVIOR_USER_DATA:
356 return MEMCACHED_FAILURE;
357 case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
358 return ptr->flags.hash_with_prefix_key;
359 case MEMCACHED_BEHAVIOR_NOREPLY:
360 return ptr->flags.no_reply;
361 case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
362 return ptr->flags.auto_eject_hosts;
363 case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
364 return ptr->flags.randomize_replica_read;
365 case MEMCACHED_BEHAVIOR_CORK:
366 return ptr->flags.cork;
367 case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
368 return ptr->flags.tcp_keepalive;
369 case MEMCACHED_BEHAVIOR_MAX:
370 default:
371 WATCHPOINT_ASSERT(0); /* Programming mistake if it gets this far */
372 return 0;
373 }
374
375 /* NOTREACHED */
376 }
377
378
379 memcached_return_t memcached_behavior_set_distribution(memcached_st *ptr, memcached_server_distribution_t type)
380 {
381 if (type < MEMCACHED_DISTRIBUTION_CONSISTENT_MAX)
382 {
383 ptr->distribution= type;
384 run_distribution(ptr);
385 }
386 else
387 {
388 return MEMCACHED_FAILURE;
389 }
390
391 return MEMCACHED_SUCCESS;
392 }
393
394
395 memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *ptr)
396 {
397 return ptr->distribution;
398 }
399
400 memcached_return_t memcached_behavior_set_key_hash(memcached_st *ptr, memcached_hash_t type)
401 {
402 hashkit_return_t rc;
403 rc= hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type);
404
405 return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
406 }
407
408 memcached_hash_t memcached_behavior_get_key_hash(memcached_st *ptr)
409 {
410 return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
411 }
412
413 memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *ptr, memcached_hash_t type)
414 {
415 hashkit_return_t rc;
416 rc= hashkit_set_function(&ptr->distribution_hashkit, (hashkit_hash_algorithm_t)type);
417
418 return rc == HASHKIT_SUCCESS ? MEMCACHED_SUCCESS : MEMCACHED_FAILURE;
419 }
420
421 memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *ptr)
422 {
423 return (memcached_hash_t)hashkit_get_function(&ptr->distribution_hashkit);
424 }