1 /*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2  *
3  *  Libmemcached library
4  *
5  *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
6  *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
7  *
8  *  Redistribution and use in source and binary forms, with or without
9  *  modification, are permitted provided that the following conditions are
10  *  met:
11  *
12  *      * Redistributions of source code must retain the above copyright
13  *  notice, this list of conditions and the following disclaimer.
14  *
15  *      * Redistributions in binary form must reproduce the above
16  *  copyright notice, this list of conditions and the following disclaimer
17  *  in the documentation and/or other materials provided with the
18  *  distribution.
19  *
20  *      * The names of its contributors may not be used to endorse or
21  *  promote products derived from this software without specific prior
22  *  written permission.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #include <libmemcached/common.h>
39 #include <libmemcached/options.hpp>
40 #include <libmemcached/virtual_bucket.h>
41 
42 #include <ctime>
43 #include <sys/types.h>
44 
memcached_is_consistent_distribution(const Memcached * memc)45 bool memcached_is_consistent_distribution(const Memcached* memc)
46 {
47   switch (memc->distribution)
48   {
49   case MEMCACHED_DISTRIBUTION_CONSISTENT:
50   case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
51   case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
52   case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
53     return true;
54 
55   case MEMCACHED_DISTRIBUTION_MODULA:
56   case MEMCACHED_DISTRIBUTION_RANDOM:
57   case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
58   case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
59     break;
60   }
61 
62   return false;
63 }
64 
65 /*
66   This function is used to modify the behavior of running client.
67 
68   We quit all connections so we can reset the sockets.
69 */
70 
memcached_behavior_set(memcached_st * shell,const memcached_behavior_t flag,uint64_t data)71 memcached_return_t memcached_behavior_set(memcached_st *shell,
72                                           const memcached_behavior_t flag,
73                                           uint64_t data)
74 {
75   Memcached* ptr= memcached2Memcached(shell);
76   if (ptr == NULL)
77   {
78     return MEMCACHED_INVALID_ARGUMENTS;
79   }
80 
81   switch (flag)
82   {
83   case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
84     ptr->number_of_replicas= (uint32_t)data;
85     break;
86 
87   case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
88     ptr->io_msg_watermark= (uint32_t) data;
89     break;
90 
91   case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
92     ptr->io_bytes_watermark= (uint32_t)data;
93     break;
94 
95   case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
96     ptr->io_key_prefetch = (uint32_t)data;
97     break;
98 
99   case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
100     ptr->snd_timeout= (int32_t)data;
101     break;
102 
103   case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
104     ptr->rcv_timeout= (int32_t)data;
105     break;
106 
107   case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
108     ptr->flags.auto_eject_hosts= bool(data);
109 
110   case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
111     if (data == 0)
112     {
113       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
114                                         memcached_literal_param("MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT requires a value greater then zero."));
115     }
116     ptr->server_failure_limit= uint32_t(data);
117     break;
118 
119   case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
120     ptr->server_timeout_limit= uint32_t(data);
121     break;
122 
123   case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
124     send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
125     if (data)
126     {
127       ptr->flags.verify_key= false;
128     }
129     ptr->flags.binary_protocol= bool(data);
130     break;
131 
132   case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
133     ptr->flags.support_cas= bool(data);
134     break;
135 
136   case MEMCACHED_BEHAVIOR_NO_BLOCK:
137     ptr->flags.no_block= bool(data);
138     send_quit(ptr);
139     break;
140 
141   case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
142     if (memcached_is_udp(ptr))
143     {
144       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
145                                  memcached_literal_param("MEMCACHED_BEHAVIOR_BUFFER_REQUESTS cannot be set while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
146     }
147     ptr->flags.buffer_requests= bool(data);
148     send_quit(ptr);
149     break;
150 
151   case MEMCACHED_BEHAVIOR_USE_UDP:
152     send_quit(ptr); // We need t shutdown all of the connections to make sure we do the correct protocol
153     ptr->flags.use_udp= bool(data);
154     if (bool(data))
155     {
156       ptr->flags.reply= false;
157       ptr->flags.buffer_requests= false;
158     }
159     else
160     {
161       ptr->flags.reply= true;
162     }
163     break;
164 
165   case MEMCACHED_BEHAVIOR_TCP_NODELAY:
166     ptr->flags.tcp_nodelay= bool(data);
167     send_quit(ptr);
168     break;
169 
170   case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
171     ptr->flags.tcp_keepalive= bool(data);
172     send_quit(ptr);
173     break;
174 
175   case MEMCACHED_BEHAVIOR_DISTRIBUTION:
176     return memcached_behavior_set_distribution(ptr, (memcached_server_distribution_t)data);
177 
178   case MEMCACHED_BEHAVIOR_KETAMA:
179     {
180       if (data) // Turn on
181       {
182         return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA);
183       }
184 
185       return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_MODULA);
186     }
187 
188   case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
189     {
190       if (bool(data) == false)
191       {
192         return memcached_behavior_set(ptr, MEMCACHED_BEHAVIOR_KETAMA, true);
193       }
194 
195       (void)memcached_behavior_set_key_hash(ptr, MEMCACHED_HASH_MD5);
196       (void)memcached_behavior_set_distribution_hash(ptr, MEMCACHED_HASH_MD5);
197       /**
198         @note We try to keep the same distribution going. This should be deprecated and rewritten.
199       */
200       return memcached_behavior_set_distribution(ptr, MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED);
201     }
202 
203   case MEMCACHED_BEHAVIOR_HASH:
204     return memcached_behavior_set_key_hash(ptr, (memcached_hash_t)(data));
205 
206   case MEMCACHED_BEHAVIOR_KETAMA_HASH:
207     return memcached_behavior_set_distribution_hash(ptr, (memcached_hash_t)(data));
208 
209   case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
210     return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
211                                       memcached_literal_param("MEMCACHED_BEHAVIOR_CACHE_LOOKUPS has been deprecated."));
212 
213   case MEMCACHED_BEHAVIOR_VERIFY_KEY:
214     if (ptr->flags.binary_protocol)
215     {
216       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
217                                         memcached_literal_param("MEMCACHED_BEHAVIOR_VERIFY_KEY if the binary protocol has been enabled."));
218     }
219     ptr->flags.verify_key= bool(data);
220     break;
221 
222   case MEMCACHED_BEHAVIOR_SORT_HOSTS:
223     {
224       ptr->flags.use_sort_hosts= bool(data);
225       return run_distribution(ptr);
226     }
227 
228   case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
229     ptr->poll_timeout= (int32_t)data;
230     break;
231 
232   case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
233     ptr->connect_timeout= (int32_t)data;
234     break;
235 
236   case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
237     ptr->retry_timeout= int32_t(data);
238     break;
239 
240   case MEMCACHED_BEHAVIOR_DEAD_TIMEOUT:
241     ptr->dead_timeout= int32_t(data);
242     break;
243 
244   case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
245     ptr->send_size= (int32_t)data;
246     send_quit(ptr);
247     break;
248 
249   case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
250     ptr->recv_size= (int32_t)data;
251     send_quit(ptr);
252     break;
253 
254   case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
255     ptr->tcp_keepidle= (uint32_t)data;
256     send_quit(ptr);
257     break;
258 
259   case MEMCACHED_BEHAVIOR_USER_DATA:
260     return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
261                                memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
262 
263   case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
264     ptr->flags.hash_with_namespace= bool(data);
265     break;
266 
267   case MEMCACHED_BEHAVIOR_NOREPLY:
268     if (memcached_is_udp(ptr) and bool(data) == false)
269     {
270       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
271                                  memcached_literal_param("MEMCACHED_BEHAVIOR_NOREPLY cannot be disabled while MEMCACHED_BEHAVIOR_USE_UDP is enabled."));
272     }
273     // We reverse the logic here to make it easier to understand throughout the
274     // code.
275     ptr->flags.reply= bool(data) ? false : true;
276     break;
277 
278   case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
279     ptr->flags.auto_eject_hosts= bool(data);
280     break;
281 
282   case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
283       srandom((uint32_t) time(NULL));
284       ptr->flags.randomize_replica_read= bool(data);
285       break;
286 
287   case MEMCACHED_BEHAVIOR_CORK:
288       return memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
289                                  memcached_literal_param("MEMCACHED_BEHAVIOR_CORK is now incorporated into the driver by default."));
290 
291   case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
292       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
293                                  memcached_literal_param("MEMCACHED_BEHAVIOR_LOAD_FROM_FILE can not be set with memcached_behavior_set()"));
294 
295   case MEMCACHED_BEHAVIOR_MAX:
296   default:
297       /* Shouldn't get here */
298       assert_msg(0, "Invalid behavior passed to memcached_behavior_set()");
299       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
300                                  memcached_literal_param("Invalid behavior passed to memcached_behavior_set()"));
301   }
302 
303   return MEMCACHED_SUCCESS;
304 }
305 
_is_auto_eject_host(const memcached_st * ptr)306 bool _is_auto_eject_host(const memcached_st *ptr)
307 {
308   return ptr->flags.auto_eject_hosts;
309 }
310 
memcached_behavior_get(memcached_st * shell,const memcached_behavior_t flag)311 uint64_t memcached_behavior_get(memcached_st *shell,
312                                 const memcached_behavior_t flag)
313 {
314   Memcached* ptr= memcached2Memcached(shell);
315   if (ptr == NULL)
316   {
317     return MEMCACHED_INVALID_ARGUMENTS;
318   }
319 
320   switch (flag)
321   {
322   case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS:
323     return ptr->number_of_replicas;
324 
325   case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK:
326     return ptr->io_msg_watermark;
327 
328   case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK:
329     return ptr->io_bytes_watermark;
330 
331   case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH:
332     return ptr->io_key_prefetch;
333 
334   case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL:
335     return ptr->flags.binary_protocol;
336 
337   case MEMCACHED_BEHAVIOR_SUPPORT_CAS:
338     return ptr->flags.support_cas;
339 
340   case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS:
341     return true;
342 
343   case MEMCACHED_BEHAVIOR_NO_BLOCK:
344     return ptr->flags.no_block;
345 
346   case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS:
347     return ptr->flags.buffer_requests;
348 
349   case MEMCACHED_BEHAVIOR_USE_UDP:
350     return memcached_is_udp(ptr);
351 
352   case MEMCACHED_BEHAVIOR_TCP_NODELAY:
353     return ptr->flags.tcp_nodelay;
354 
355   case MEMCACHED_BEHAVIOR_VERIFY_KEY:
356     return ptr->flags.verify_key;
357 
358   case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED:
359     if (memcached_is_consistent_distribution(ptr))
360     {
361       return memcached_is_weighted_ketama(ptr);
362     }
363     return false;
364 
365   case MEMCACHED_BEHAVIOR_DISTRIBUTION:
366     return ptr->distribution;
367 
368   case MEMCACHED_BEHAVIOR_KETAMA:
369     return memcached_is_consistent_distribution(ptr);
370 
371   case MEMCACHED_BEHAVIOR_HASH:
372     return hashkit_get_function(&ptr->hashkit);
373 
374   case MEMCACHED_BEHAVIOR_KETAMA_HASH:
375     return hashkit_get_function(&ptr->hashkit);
376 
377   case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS:
378   case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT:
379     return ptr->server_failure_limit;
380 
381   case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT:
382     return ptr->server_timeout_limit;
383 
384   case MEMCACHED_BEHAVIOR_SORT_HOSTS:
385     return ptr->flags.use_sort_hosts;
386 
387   case MEMCACHED_BEHAVIOR_POLL_TIMEOUT:
388     return (uint64_t)ptr->poll_timeout;
389 
390   case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT:
391     return (uint64_t)ptr->connect_timeout;
392 
393   case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT:
394     return (uint64_t)ptr->retry_timeout;
395 
396   case MEMCACHED_BEHAVIOR_DEAD_TIMEOUT:
397     return uint64_t(ptr->dead_timeout);
398 
399   case MEMCACHED_BEHAVIOR_SND_TIMEOUT:
400     return (uint64_t)ptr->snd_timeout;
401 
402   case MEMCACHED_BEHAVIOR_RCV_TIMEOUT:
403     return (uint64_t)ptr->rcv_timeout;
404 
405   case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE:
406     return (uint64_t)ptr->tcp_keepidle;
407 
408   case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE:
409     {
410       int sock_size= 0;
411       socklen_t sock_length= sizeof(int);
412 
413       if (ptr->send_size != -1) // If value is -1 then we are using the default
414       {
415         return (uint64_t) ptr->send_size;
416       }
417 
418       memcached_instance_st* instance= memcached_instance_fetch(ptr, 0);
419 
420       if (instance) // If we have an instance we test, otherwise we just set and pray
421       {
422         /* REFACTOR */
423         /* We just try the first host, and if it is down we return zero */
424         if (memcached_failed(memcached_connect(instance)))
425         {
426           return 0;
427         }
428 
429         if (memcached_failed(memcached_io_wait_for_write(instance)))
430         {
431           return 0;
432         }
433 
434         if (getsockopt(instance->fd, SOL_SOCKET, SO_SNDBUF, (char*)&sock_size, &sock_length) < 0)
435         {
436           memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
437           return 0; /* Zero means error */
438         }
439       }
440 
441       return (uint64_t) sock_size;
442     }
443 
444   case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE:
445     {
446       int sock_size= 0;
447       socklen_t sock_length= sizeof(int);
448 
449       if (ptr->recv_size != -1) // If value is -1 then we are using the default
450         return (uint64_t) ptr->recv_size;
451 
452       memcached_instance_st* instance= memcached_instance_fetch(ptr, 0);
453 
454       /**
455         @note REFACTOR
456       */
457       if (instance)
458       {
459         /* We just try the first host, and if it is down we return zero */
460         if (memcached_failed(memcached_connect(instance)))
461         {
462           return 0;
463         }
464 
465         if (memcached_failed(memcached_io_wait_for_write(instance)))
466         {
467           return 0;
468         }
469 
470         if (getsockopt(instance->fd, SOL_SOCKET, SO_RCVBUF, (char*)&sock_size, &sock_length) < 0)
471         {
472           memcached_set_errno(*ptr, get_socket_errno(), MEMCACHED_AT);
473           return 0; /* Zero means error */
474         }
475       }
476 
477       return (uint64_t) sock_size;
478     }
479 
480   case MEMCACHED_BEHAVIOR_USER_DATA:
481     memcached_set_error(*ptr, MEMCACHED_DEPRECATED, MEMCACHED_AT,
482                         memcached_literal_param("MEMCACHED_BEHAVIOR_USER_DATA deprecated."));
483     return 0;
484 
485   case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY:
486     return ptr->flags.hash_with_namespace;
487 
488   case MEMCACHED_BEHAVIOR_NOREPLY:
489     return ptr->flags.reply ? false : true;
490 
491   case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS:
492     return ptr->flags.auto_eject_hosts;
493 
494   case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ:
495     return ptr->flags.randomize_replica_read;
496 
497   case MEMCACHED_BEHAVIOR_CORK:
498 #ifdef HAVE_MSG_MORE
499     return true;
500 #else
501     return false;
502 #endif
503 
504   case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE:
505     return ptr->flags.tcp_keepalive;
506 
507   case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE:
508     return bool(memcached_parse_filename(ptr));
509 
510   case MEMCACHED_BEHAVIOR_MAX:
511   default:
512     assert_msg(0, "Invalid behavior passed to memcached_behavior_get()");
513     return 0;
514   }
515 
516   /* NOTREACHED */
517 }
518 
519 
memcached_behavior_set_distribution(memcached_st * shell,memcached_server_distribution_t type)520 memcached_return_t memcached_behavior_set_distribution(memcached_st *shell, memcached_server_distribution_t type)
521 {
522   Memcached* ptr= memcached2Memcached(shell);
523   if (ptr)
524   {
525     switch (type)
526     {
527     case MEMCACHED_DISTRIBUTION_MODULA:
528       break;
529 
530     case MEMCACHED_DISTRIBUTION_CONSISTENT:
531     case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
532       memcached_set_weighted_ketama(ptr, false);
533       break;
534 
535     case MEMCACHED_DISTRIBUTION_RANDOM:
536       break;
537 
538     case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY:
539       break;
540 
541     case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED:
542       memcached_set_weighted_ketama(ptr, true);
543       break;
544 
545     case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET:
546       break;
547 
548     default:
549     case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX:
550       return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
551                                  memcached_literal_param("Invalid memcached_server_distribution_t"));
552     }
553     ptr->distribution= type;
554 
555     return run_distribution(ptr);
556   }
557 
558   return MEMCACHED_INVALID_ARGUMENTS;
559 }
560 
561 
memcached_behavior_get_distribution(memcached_st * shell)562 memcached_server_distribution_t memcached_behavior_get_distribution(memcached_st *shell)
563 {
564   Memcached* ptr= memcached2Memcached(shell);
565   if (ptr)
566   {
567     return ptr->distribution;
568   }
569 
570   return MEMCACHED_DISTRIBUTION_CONSISTENT_MAX;
571 }
572 
memcached_behavior_set_key_hash(memcached_st * shell,memcached_hash_t type)573 memcached_return_t memcached_behavior_set_key_hash(memcached_st *shell, memcached_hash_t type)
574 {
575   Memcached* ptr= memcached2Memcached(shell);
576   if (ptr)
577   {
578     if (hashkit_success(hashkit_set_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
579     {
580       return MEMCACHED_SUCCESS;
581     }
582 
583     return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
584                                memcached_literal_param("Invalid memcached_hash_t()"));
585   }
586 
587   return MEMCACHED_INVALID_ARGUMENTS;
588 }
589 
memcached_behavior_get_key_hash(memcached_st * shell)590 memcached_hash_t memcached_behavior_get_key_hash(memcached_st *shell)
591 {
592   Memcached* ptr= memcached2Memcached(shell);
593   if (ptr)
594   {
595     return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
596   }
597 
598   return MEMCACHED_HASH_MAX;
599 }
600 
memcached_behavior_set_distribution_hash(memcached_st * shell,memcached_hash_t type)601 memcached_return_t memcached_behavior_set_distribution_hash(memcached_st *shell, memcached_hash_t type)
602 {
603   Memcached* ptr= memcached2Memcached(shell);
604   if (ptr)
605   {
606     if (hashkit_success(hashkit_set_distribution_function(&ptr->hashkit, (hashkit_hash_algorithm_t)type)))
607     {
608       return MEMCACHED_SUCCESS;
609     }
610 
611     return memcached_set_error(*ptr, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
612                                memcached_literal_param("Invalid memcached_hash_t()"));
613   }
614 
615   return MEMCACHED_INVALID_ARGUMENTS;
616 }
617 
memcached_behavior_get_distribution_hash(memcached_st * shell)618 memcached_hash_t memcached_behavior_get_distribution_hash(memcached_st *shell)
619 {
620   Memcached* ptr= memcached2Memcached(shell);
621   if (ptr)
622   {
623     return (memcached_hash_t)hashkit_get_function(&ptr->hashkit);
624   }
625 
626   return MEMCACHED_HASH_MAX;
627 }
628 
libmemcached_string_behavior(const memcached_behavior_t flag)629 const char *libmemcached_string_behavior(const memcached_behavior_t flag)
630 {
631   switch (flag)
632   {
633   case MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_TIMEOUT_LIMIT";
634   case MEMCACHED_BEHAVIOR_NO_BLOCK: return "MEMCACHED_BEHAVIOR_NO_BLOCK";
635   case MEMCACHED_BEHAVIOR_TCP_NODELAY: return "MEMCACHED_BEHAVIOR_TCP_NODELAY";
636   case MEMCACHED_BEHAVIOR_HASH: return "MEMCACHED_BEHAVIOR_HASH";
637   case MEMCACHED_BEHAVIOR_KETAMA: return "MEMCACHED_BEHAVIOR_KETAMA";
638   case MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_SEND_SIZE";
639   case MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE: return "MEMCACHED_BEHAVIOR_SOCKET_RECV_SIZE";
640   case MEMCACHED_BEHAVIOR_CACHE_LOOKUPS: return "MEMCACHED_BEHAVIOR_CACHE_LOOKUPS";
641   case MEMCACHED_BEHAVIOR_SUPPORT_CAS: return "MEMCACHED_BEHAVIOR_SUPPORT_CAS";
642   case MEMCACHED_BEHAVIOR_POLL_TIMEOUT: return "MEMCACHED_BEHAVIOR_POLL_TIMEOUT";
643   case MEMCACHED_BEHAVIOR_DISTRIBUTION: return "MEMCACHED_BEHAVIOR_DISTRIBUTION";
644   case MEMCACHED_BEHAVIOR_BUFFER_REQUESTS: return "MEMCACHED_BEHAVIOR_BUFFER_REQUESTS";
645   case MEMCACHED_BEHAVIOR_USER_DATA: return "MEMCACHED_BEHAVIOR_USER_DATA";
646   case MEMCACHED_BEHAVIOR_SORT_HOSTS: return "MEMCACHED_BEHAVIOR_SORT_HOSTS";
647   case MEMCACHED_BEHAVIOR_VERIFY_KEY: return "MEMCACHED_BEHAVIOR_VERIFY_KEY";
648   case MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT: return "MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT";
649   case MEMCACHED_BEHAVIOR_RETRY_TIMEOUT: return "MEMCACHED_BEHAVIOR_RETRY_TIMEOUT";
650   case MEMCACHED_BEHAVIOR_DEAD_TIMEOUT: return "MEMCACHED_BEHAVIOR_DEAD_TIMEOUT";
651   case MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED: return "MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED";
652   case MEMCACHED_BEHAVIOR_KETAMA_HASH: return "MEMCACHED_BEHAVIOR_KETAMA_HASH";
653   case MEMCACHED_BEHAVIOR_BINARY_PROTOCOL: return "MEMCACHED_BEHAVIOR_BINARY_PROTOCOL";
654   case MEMCACHED_BEHAVIOR_SND_TIMEOUT: return "MEMCACHED_BEHAVIOR_SND_TIMEOUT";
655   case MEMCACHED_BEHAVIOR_RCV_TIMEOUT: return "MEMCACHED_BEHAVIOR_RCV_TIMEOUT";
656   case MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT: return "MEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMIT";
657   case MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_MSG_WATERMARK";
658   case MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK: return "MEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK";
659   case MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH: return "MEMCACHED_BEHAVIOR_IO_KEY_PREFETCH";
660   case MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY: return "MEMCACHED_BEHAVIOR_HASH_WITH_PREFIX_KEY";
661   case MEMCACHED_BEHAVIOR_NOREPLY: return "MEMCACHED_BEHAVIOR_NOREPLY";
662   case MEMCACHED_BEHAVIOR_USE_UDP: return "MEMCACHED_BEHAVIOR_USE_UDP";
663   case MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS: return "MEMCACHED_BEHAVIOR_AUTO_EJECT_HOSTS";
664   case MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS: return "MEMCACHED_BEHAVIOR_REMOVE_FAILED_SERVERS";
665   case MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS: return "MEMCACHED_BEHAVIOR_NUMBER_OF_REPLICAS";
666   case MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ: return "MEMCACHED_BEHAVIOR_RANDOMIZE_REPLICA_READ";
667   case MEMCACHED_BEHAVIOR_CORK: return "MEMCACHED_BEHAVIOR_CORK";
668   case MEMCACHED_BEHAVIOR_TCP_KEEPALIVE: return "MEMCACHED_BEHAVIOR_TCP_KEEPALIVE";
669   case MEMCACHED_BEHAVIOR_TCP_KEEPIDLE: return "MEMCACHED_BEHAVIOR_TCP_KEEPIDLE";
670   case MEMCACHED_BEHAVIOR_LOAD_FROM_FILE: return "MEMCACHED_BEHAVIOR_LOAD_FROM_FILE";
671   default:
672   case MEMCACHED_BEHAVIOR_MAX: return "INVALID memcached_behavior_t";
673   }
674 }
675 
libmemcached_string_distribution(const memcached_server_distribution_t flag)676 const char *libmemcached_string_distribution(const memcached_server_distribution_t flag)
677 {
678   switch (flag)
679   {
680   case MEMCACHED_DISTRIBUTION_MODULA: return "MEMCACHED_DISTRIBUTION_MODULA";
681   case MEMCACHED_DISTRIBUTION_CONSISTENT: return "MEMCACHED_DISTRIBUTION_CONSISTENT";
682   case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA";
683   case MEMCACHED_DISTRIBUTION_RANDOM: return "MEMCACHED_DISTRIBUTION_RANDOM";
684   case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY: return "MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY";
685   case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED: return "MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED";
686   case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET: return "MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET";
687   default:
688   case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX: return "INVALID memcached_server_distribution_t";
689   }
690 }
691 
memcached_bucket_set(memcached_st * shell,const uint32_t * host_map,const uint32_t * forward_map,const uint32_t buckets,const uint32_t replicas)692 memcached_return_t memcached_bucket_set(memcached_st *shell,
693                                         const uint32_t *host_map,
694                                         const uint32_t *forward_map,
695                                         const uint32_t buckets,
696                                         const uint32_t replicas)
697 {
698   Memcached* self= memcached2Memcached(shell);
699   memcached_return_t rc;
700 
701   if (self == NULL)
702   {
703     return MEMCACHED_INVALID_ARGUMENTS;
704   }
705 
706   if (host_map == NULL)
707   {
708     return MEMCACHED_INVALID_ARGUMENTS;
709   }
710 
711   memcached_server_distribution_t old= memcached_behavior_get_distribution(self);
712 
713   if (memcached_failed(rc =memcached_behavior_set_distribution(self, MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET)))
714   {
715     return rc;
716   }
717 
718   if (memcached_failed(rc= memcached_virtual_bucket_create(self, host_map, forward_map, buckets, replicas)))
719   {
720     memcached_behavior_set_distribution(self, old);
721   }
722 
723   return rc;
724 }
725