2 +--------------------------------------------------------------------+
3 | libmemcached-awesome - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020-2021 Michael Wallner https://awesome.co/ |
13 +--------------------------------------------------------------------+
16 #include "libmemcached/common.h"
17 #include "libmemcached/virtual_bucket.h"
18 #include "p9y/gettimeofday.hpp"
19 #include "p9y/random.hpp"
21 uint32_t memcached_generate_hash_value(const char *key
, size_t key_length
,
22 memcached_hash_t hash_algorithm
) {
23 return libhashkit_digest(key
, key_length
, (hashkit_hash_algorithm_t
) hash_algorithm
);
26 static inline uint32_t generate_hash(const Memcached
*ptr
, const char *key
, size_t key_length
) {
27 return hashkit_digest(&ptr
->hashkit
, key
, key_length
);
30 static uint32_t dispatch_host(const Memcached
*ptr
, uint32_t hash
) {
31 switch (ptr
->distribution
) {
32 case MEMCACHED_DISTRIBUTION_CONSISTENT
:
33 case MEMCACHED_DISTRIBUTION_CONSISTENT_WEIGHTED
:
34 case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA
:
35 case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY
: {
36 uint32_t num
= ptr
->ketama
.continuum_points_counter
;
37 WATCHPOINT_ASSERT(ptr
->ketama
.continuum
);
39 memcached_continuum_item_st
*begin
, *end
, *left
, *right
, *middle
;
40 begin
= left
= ptr
->ketama
.continuum
;
41 end
= right
= ptr
->ketama
.continuum
+ num
;
43 while (left
< right
) {
44 middle
= left
+ (right
- left
) / 2;
45 if (middle
->value
< hash
)
54 case MEMCACHED_DISTRIBUTION_MODULA
:
55 return hash
% memcached_server_count(ptr
);
56 case MEMCACHED_DISTRIBUTION_RANDOM
:
57 return (uint32_t) random() % memcached_server_count(ptr
);
58 case MEMCACHED_DISTRIBUTION_VIRTUAL_BUCKET
: {
59 return memcached_virtual_bucket_get(ptr
, hash
);
62 case MEMCACHED_DISTRIBUTION_CONSISTENT_MAX
:
63 WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
64 return hash
% memcached_server_count(ptr
);
70 One version is public and will not modify the distribution hash, the other will.
72 static inline uint32_t _generate_hash_wrapper(const Memcached
*ptr
, const char *key
,
74 WATCHPOINT_ASSERT(memcached_server_count(ptr
));
76 if (memcached_server_count(ptr
) == 1)
79 if (ptr
->flags
.hash_with_namespace
) {
80 size_t temp_length
= memcached_array_size(ptr
->_namespace
) + key_length
;
81 char temp
[MEMCACHED_MAX_KEY
];
83 if (temp_length
> MEMCACHED_MAX_KEY
- 1)
86 strncpy(temp
, memcached_array_string(ptr
->_namespace
), memcached_array_size(ptr
->_namespace
));
87 strncpy(temp
+ memcached_array_size(ptr
->_namespace
), key
, key_length
);
89 return generate_hash(ptr
, temp
, temp_length
);
91 return generate_hash(ptr
, key
, key_length
);
95 static inline void _regen_for_auto_eject(Memcached
*ptr
) {
96 if (_is_auto_eject_host(ptr
) && ptr
->ketama
.next_distribution_rebuild
) {
99 if (gettimeofday(&now
, NULL
) == 0 and now
.tv_sec
> ptr
->ketama
.next_distribution_rebuild
) {
100 run_distribution(ptr
);
105 void memcached_autoeject(memcached_st
*ptr
) {
106 _regen_for_auto_eject(ptr
);
109 uint32_t memcached_generate_hash_with_redistribution(memcached_st
*ptr
, const char *key
,
111 uint32_t hash
= _generate_hash_wrapper(ptr
, key
, key_length
);
113 _regen_for_auto_eject(ptr
);
115 return dispatch_host(ptr
, hash
);
118 uint32_t memcached_generate_hash(const memcached_st
*shell
, const char *key
, size_t key_length
) {
119 const Memcached
*ptr
= memcached2Memcached(shell
);
121 return dispatch_host(ptr
, _generate_hash_wrapper(ptr
, key
, key_length
));
127 const hashkit_st
*memcached_get_hashkit(const memcached_st
*shell
) {
128 const Memcached
*ptr
= memcached2Memcached(shell
);
130 return &ptr
->hashkit
;
136 memcached_return_t
memcached_set_hashkit(memcached_st
*shell
, hashkit_st
*hashk
) {
137 Memcached
*self
= memcached2Memcached(shell
);
139 hashkit_free(&self
->hashkit
);
140 hashkit_clone(&self
->hashkit
, hashk
);
142 return MEMCACHED_SUCCESS
;
145 return MEMCACHED_INVALID_ARGUMENTS
;
148 const char *libmemcached_string_hash(memcached_hash_t type
) {
149 return libhashkit_string_hash((hashkit_hash_algorithm_t
) type
);