nutcracker 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. data/README.md +22 -0
  2. data/Rakefile +55 -0
  3. data/bin/nutcracker +2 -0
  4. data/ext/nutcracker/ChangeLog +66 -0
  5. data/ext/nutcracker/LICENSE +177 -0
  6. data/ext/nutcracker/Makefile.am +7 -0
  7. data/ext/nutcracker/Makefile.in +726 -0
  8. data/ext/nutcracker/NOTICE +124 -0
  9. data/ext/nutcracker/README.md +240 -0
  10. data/ext/nutcracker/aclocal.m4 +956 -0
  11. data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
  12. data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
  13. data/ext/nutcracker/conf/nutcracker.yml +67 -0
  14. data/ext/nutcracker/config.h.in +316 -0
  15. data/ext/nutcracker/config/config.guess +1561 -0
  16. data/ext/nutcracker/config/config.sub +1686 -0
  17. data/ext/nutcracker/config/depcomp +630 -0
  18. data/ext/nutcracker/config/install-sh +520 -0
  19. data/ext/nutcracker/config/ltmain.sh +8413 -0
  20. data/ext/nutcracker/config/missing +376 -0
  21. data/ext/nutcracker/configure +18862 -0
  22. data/ext/nutcracker/configure.ac +155 -0
  23. data/ext/nutcracker/contrib/Makefile.am +3 -0
  24. data/ext/nutcracker/contrib/Makefile.in +560 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
  31. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
  32. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
  33. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
  34. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  71. data/ext/nutcracker/extconf.rb +5 -0
  72. data/ext/nutcracker/m4/libtool.m4 +7376 -0
  73. data/ext/nutcracker/m4/ltoptions.m4 +368 -0
  74. data/ext/nutcracker/m4/ltsugar.m4 +123 -0
  75. data/ext/nutcracker/m4/ltversion.m4 +23 -0
  76. data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
  77. data/ext/nutcracker/notes/c-styleguide.txt +425 -0
  78. data/ext/nutcracker/notes/debug.txt +96 -0
  79. data/ext/nutcracker/notes/memcache.txt +123 -0
  80. data/ext/nutcracker/notes/recommendation.md +118 -0
  81. data/ext/nutcracker/notes/redis.md +415 -0
  82. data/ext/nutcracker/notes/socket.txt +131 -0
  83. data/ext/nutcracker/scripts/multi_get.sh +26 -0
  84. data/ext/nutcracker/scripts/nutcracker.init +73 -0
  85. data/ext/nutcracker/scripts/nutcracker.spec +52 -0
  86. data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
  87. data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
  88. data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
  89. data/ext/nutcracker/scripts/redis-check.py +23 -0
  90. data/ext/nutcracker/scripts/redis-check.sh +564 -0
  91. data/ext/nutcracker/src/Makefile.am +46 -0
  92. data/ext/nutcracker/src/Makefile.in +726 -0
  93. data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
  94. data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
  95. data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
  96. data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
  97. data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
  98. data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
  99. data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
  100. data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
  101. data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
  102. data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
  103. data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
  104. data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
  105. data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
  106. data/ext/nutcracker/src/nc.c +573 -0
  107. data/ext/nutcracker/src/nc_array.c +204 -0
  108. data/ext/nutcracker/src/nc_array.h +73 -0
  109. data/ext/nutcracker/src/nc_client.c +189 -0
  110. data/ext/nutcracker/src/nc_client.h +28 -0
  111. data/ext/nutcracker/src/nc_conf.c +1766 -0
  112. data/ext/nutcracker/src/nc_conf.h +134 -0
  113. data/ext/nutcracker/src/nc_connection.c +392 -0
  114. data/ext/nutcracker/src/nc_connection.h +99 -0
  115. data/ext/nutcracker/src/nc_core.c +334 -0
  116. data/ext/nutcracker/src/nc_core.h +131 -0
  117. data/ext/nutcracker/src/nc_event.c +214 -0
  118. data/ext/nutcracker/src/nc_event.h +39 -0
  119. data/ext/nutcracker/src/nc_log.c +254 -0
  120. data/ext/nutcracker/src/nc_log.h +120 -0
  121. data/ext/nutcracker/src/nc_mbuf.c +285 -0
  122. data/ext/nutcracker/src/nc_mbuf.h +67 -0
  123. data/ext/nutcracker/src/nc_message.c +828 -0
  124. data/ext/nutcracker/src/nc_message.h +253 -0
  125. data/ext/nutcracker/src/nc_proxy.c +359 -0
  126. data/ext/nutcracker/src/nc_proxy.h +34 -0
  127. data/ext/nutcracker/src/nc_queue.h +788 -0
  128. data/ext/nutcracker/src/nc_rbtree.c +348 -0
  129. data/ext/nutcracker/src/nc_rbtree.h +47 -0
  130. data/ext/nutcracker/src/nc_request.c +588 -0
  131. data/ext/nutcracker/src/nc_response.c +332 -0
  132. data/ext/nutcracker/src/nc_server.c +841 -0
  133. data/ext/nutcracker/src/nc_server.h +143 -0
  134. data/ext/nutcracker/src/nc_signal.c +131 -0
  135. data/ext/nutcracker/src/nc_signal.h +34 -0
  136. data/ext/nutcracker/src/nc_stats.c +1188 -0
  137. data/ext/nutcracker/src/nc_stats.h +206 -0
  138. data/ext/nutcracker/src/nc_string.c +109 -0
  139. data/ext/nutcracker/src/nc_string.h +112 -0
  140. data/ext/nutcracker/src/nc_util.c +619 -0
  141. data/ext/nutcracker/src/nc_util.h +214 -0
  142. data/ext/nutcracker/src/proto/Makefile.am +14 -0
  143. data/ext/nutcracker/src/proto/Makefile.in +482 -0
  144. data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
  145. data/ext/nutcracker/src/proto/nc_proto.h +155 -0
  146. data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
  147. data/lib/nutcracker.rb +7 -0
  148. data/lib/nutcracker/version.rb +3 -0
  149. metadata +194 -0
@@ -0,0 +1,144 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <stdio.h>
19
+ #include <stdlib.h>
20
+
21
+ #include <nc_core.h>
22
+ #include <nc_server.h>
23
+ #include <nc_hashkit.h>
24
+
25
+ #define MODULA_CONTINUUM_ADDITION 10 /* # extra slots to build into continuum */
26
+ #define MODULA_POINTS_PER_SERVER 1
27
+
28
+ rstatus_t
29
+ modula_update(struct server_pool *pool)
30
+ {
31
+ uint32_t nserver; /* # server - live and dead */
32
+ uint32_t nlive_server; /* # live server */
33
+ uint32_t pointer_per_server; /* pointers per server proportional to weight */
34
+ uint32_t pointer_counter; /* # pointers on continuum */
35
+ uint32_t points_per_server; /* points per server */
36
+ uint32_t continuum_index; /* continuum index */
37
+ uint32_t continuum_addition; /* extra space in the continuum */
38
+ uint32_t server_index; /* server index */
39
+ int64_t now; /* current timestamp in usec */
40
+
41
+ now = nc_usec_now();
42
+ if (now < 0) {
43
+ return NC_ERROR;
44
+ }
45
+
46
+ nserver = array_n(&pool->server);
47
+ nlive_server = 0;
48
+ pool->next_rebuild = 0LL;
49
+
50
+ for (server_index = 0; server_index < nserver; server_index++) {
51
+ struct server *server = array_get(&pool->server, server_index);
52
+
53
+ if (pool->auto_eject_hosts) {
54
+ if (server->next_retry <= now) {
55
+ server->next_retry = 0LL;
56
+ nlive_server++;
57
+ } else if (pool->next_rebuild == 0LL ||
58
+ server->next_retry < pool->next_rebuild) {
59
+ pool->next_rebuild = server->next_retry;
60
+ }
61
+ } else {
62
+ nlive_server++;
63
+ }
64
+ }
65
+
66
+ pool->nlive_server = nlive_server;
67
+
68
+ if (nlive_server == 0) {
69
+ ASSERT(pool->continuum != NULL);
70
+ ASSERT(pool->ncontinuum != 0);
71
+
72
+ log_debug(LOG_DEBUG, "no live servers for pool %"PRIu32" '%.*s'",
73
+ pool->idx, pool->name.len, pool->name.data);
74
+
75
+ return NC_OK;
76
+ }
77
+ log_debug(LOG_DEBUG, "%"PRIu32" of %"PRIu32" servers are live for pool "
78
+ "%"PRIu32" '%.*s'", nlive_server, nserver, pool->idx,
79
+ pool->name.len, pool->name.data);
80
+
81
+ continuum_addition = MODULA_CONTINUUM_ADDITION;
82
+ points_per_server = MODULA_POINTS_PER_SERVER;
83
+
84
+ /*
85
+ * Allocate the continuum for the pool, the first time, and every time we
86
+ * add a new server to the pool
87
+ */
88
+ if (nlive_server > pool->nserver_continuum) {
89
+ struct continuum *continuum;
90
+ uint32_t nserver_continuum = nlive_server + MODULA_CONTINUUM_ADDITION;
91
+ uint32_t ncontinuum = nserver_continuum * MODULA_POINTS_PER_SERVER;
92
+
93
+ continuum = nc_realloc(pool->continuum, sizeof(*continuum) * ncontinuum);
94
+ if (continuum == NULL) {
95
+ return NC_ENOMEM;
96
+ }
97
+
98
+ pool->continuum = continuum;
99
+ pool->nserver_continuum = nserver_continuum;
100
+ /* pool->ncontinuum is initialized later as it could be <= ncontinuum */
101
+ }
102
+
103
+ /* update the continuum with the servers that are live */
104
+ continuum_index = 0;
105
+ pointer_counter = 0;
106
+ for (server_index = 0; server_index < nserver; server_index++) {
107
+ struct server *server = array_get(&pool->server, server_index);
108
+
109
+ if (pool->auto_eject_hosts && server->next_retry > now) {
110
+ continue;
111
+ }
112
+
113
+ pointer_per_server = 1;
114
+
115
+ pool->continuum[continuum_index].index = server_index;
116
+ pool->continuum[continuum_index++].value = 0;
117
+
118
+ pointer_counter += pointer_per_server;
119
+ }
120
+ pool->ncontinuum = pointer_counter;
121
+
122
+ log_debug(LOG_VERB, "updated pool %"PRIu32" '%.*s' with %"PRIu32" of "
123
+ "%"PRIu32" servers live in %"PRIu32" slots and %"PRIu32" "
124
+ "active points in %"PRIu32" slots", pool->idx,
125
+ pool->name.len, pool->name.data, nlive_server, nserver,
126
+ pool->nserver_continuum, pool->ncontinuum,
127
+ (pool->nserver_continuum + continuum_addition) * points_per_server);
128
+
129
+ return NC_OK;
130
+
131
+ }
132
+
133
+ uint32_t
134
+ modula_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash)
135
+ {
136
+ struct continuum *c;
137
+
138
+ ASSERT(continuum != NULL);
139
+ ASSERT(ncontinuum != 0);
140
+
141
+ c = continuum + hash % ncontinuum;
142
+
143
+ return c->index;
144
+ }
@@ -0,0 +1,99 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /*
19
+ * "Murmur" hash provided by Austin, tanjent@gmail.com
20
+ * http://murmurhash.googlepages.com/
21
+ *
22
+ * Note - This code makes a few assumptions about how your machine behaves -
23
+ *
24
+ * 1. We can read a 4-byte value from any address without crashing
25
+ * 2. sizeof(int) == 4
26
+ *
27
+ * And it has a few limitations -
28
+ * 1. It will not work incrementally.
29
+ * 2. It will not produce the same results on little-endian and big-endian
30
+ * machines.
31
+ *
32
+ * Updated to murmur2 hash - BP
33
+ */
34
+
35
+ #include <nc_core.h>
36
+
37
+ uint32_t
38
+ hash_murmur(const char *key, size_t length)
39
+ {
40
+ /*
41
+ * 'm' and 'r' are mixing constants generated offline. They're not
42
+ * really 'magic', they just happen to work well.
43
+ */
44
+
45
+ const unsigned int m = 0x5bd1e995;
46
+ const uint32_t seed = (0xdeadbeef * (uint32_t)length);
47
+ const int r = 24;
48
+
49
+
50
+ /* Initialize the hash to a 'random' value */
51
+
52
+ uint32_t h = seed ^ (uint32_t)length;
53
+
54
+ /* Mix 4 bytes at a time into the hash */
55
+
56
+ const unsigned char * data = (const unsigned char *)key;
57
+
58
+ while (length >= 4) {
59
+ unsigned int k = *(unsigned int *)data;
60
+
61
+ k *= m;
62
+ k ^= k >> r;
63
+ k *= m;
64
+
65
+ h *= m;
66
+ h ^= k;
67
+
68
+ data += 4;
69
+ length -= 4;
70
+ }
71
+
72
+ /* Handle the last few bytes of the input array */
73
+
74
+ switch(length) {
75
+ case 3:
76
+ h ^= ((uint32_t)data[2]) << 16;
77
+
78
+ case 2:
79
+ h ^= ((uint32_t)data[1]) << 8;
80
+
81
+ case 1:
82
+ h ^= data[0];
83
+ h *= m;
84
+
85
+ default:
86
+ break;
87
+ };
88
+
89
+ /*
90
+ * Do a few final mixes of the hash to ensure the last few bytes are
91
+ * well-incorporated.
92
+ */
93
+
94
+ h ^= h >> 13;
95
+ h *= m;
96
+ h ^= h >> 15;
97
+
98
+ return h;
99
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ /*
19
+ * HashKit
20
+ * Copyright (C) 2009 Brian Aker
21
+ * All rights reserved.
22
+ *
23
+ * Use and distribution licensed under the BSD license. See
24
+ * the COPYING file in the parent directory for full text.
25
+ */
26
+
27
+ /*
28
+ * This has is Jenkin's "One at A time Hash".
29
+ * http://en.wikipedia.org/wiki/Jenkins_hash_function
30
+ */
31
+
32
+ #include <nc_core.h>
33
+
34
+ uint32_t
35
+ hash_one_at_a_time(const char *key, size_t key_length)
36
+ {
37
+ const char *ptr = key;
38
+ uint32_t value = 0;
39
+
40
+ while (key_length--) {
41
+ uint32_t val = (uint32_t) *ptr++;
42
+ value += val;
43
+ value += (value << 10);
44
+ value ^= (value >> 6);
45
+ }
46
+ value += (value << 3);
47
+ value ^= (value >> 11);
48
+ value += (value << 15);
49
+
50
+ return value;
51
+ }
@@ -0,0 +1,146 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <stdio.h>
19
+ #include <stdlib.h>
20
+
21
+ #include <nc_core.h>
22
+ #include <nc_server.h>
23
+ #include <nc_hashkit.h>
24
+
25
+ #define RANDOM_CONTINUUM_ADDITION 10 /* # extra slots to build into continuum */
26
+ #define RANDOM_POINTS_PER_SERVER 1
27
+
28
+ rstatus_t
29
+ random_update(struct server_pool *pool)
30
+ {
31
+ uint32_t nserver; /* # server - live and dead */
32
+ uint32_t nlive_server; /* # live server */
33
+ uint32_t pointer_per_server; /* pointers per server proportional to weight */
34
+ uint32_t pointer_counter; /* # pointers on continuum */
35
+ uint32_t points_per_server; /* points per server */
36
+ uint32_t continuum_index; /* continuum index */
37
+ uint32_t continuum_addition; /* extra space in the continuum */
38
+ uint32_t server_index; /* server index */
39
+ int64_t now; /* current timestamp in usec */
40
+
41
+ now = nc_usec_now();
42
+ if (now < 0) {
43
+ return NC_ERROR;
44
+ }
45
+
46
+ nserver = array_n(&pool->server);
47
+ nlive_server = 0;
48
+ pool->next_rebuild = 0LL;
49
+
50
+ for (server_index = 0; server_index < nserver; server_index++) {
51
+ struct server *server = array_get(&pool->server, server_index);
52
+
53
+ if (pool->auto_eject_hosts) {
54
+ if (server->next_retry <= now) {
55
+ server->next_retry = 0LL;
56
+ nlive_server++;
57
+ } else if (pool->next_rebuild == 0LL ||
58
+ server->next_retry < pool->next_rebuild) {
59
+ pool->next_rebuild = server->next_retry;
60
+ }
61
+ } else {
62
+ nlive_server++;
63
+ }
64
+ }
65
+
66
+ pool->nlive_server = nlive_server;
67
+
68
+ if (nlive_server == 0) {
69
+ ASSERT(pool->continuum != NULL);
70
+ ASSERT(pool->ncontinuum != 0);
71
+
72
+ log_debug(LOG_DEBUG, "no live servers for pool %"PRIu32" '%.*s'",
73
+ pool->idx, pool->name.len, pool->name.data);
74
+
75
+ return NC_OK;
76
+ }
77
+ log_debug(LOG_DEBUG, "%"PRIu32" of %"PRIu32" servers are live for pool "
78
+ "%"PRIu32" '%.*s'", nlive_server, nserver, pool->idx,
79
+ pool->name.len, pool->name.data);
80
+
81
+ continuum_addition = RANDOM_CONTINUUM_ADDITION;
82
+ points_per_server = RANDOM_POINTS_PER_SERVER;
83
+
84
+ /*
85
+ * Allocate the continuum for the pool, the first time, and every time we
86
+ * add a new server to the pool
87
+ */
88
+ if (nlive_server > pool->nserver_continuum) {
89
+ struct continuum *continuum;
90
+ uint32_t nserver_continuum = nlive_server + RANDOM_CONTINUUM_ADDITION;
91
+ uint32_t ncontinuum = nserver_continuum * RANDOM_POINTS_PER_SERVER;
92
+
93
+ continuum = nc_realloc(pool->continuum, sizeof(*continuum) * ncontinuum);
94
+ if (continuum == NULL) {
95
+ return NC_ENOMEM;
96
+ }
97
+
98
+ srandom((uint32_t)time(NULL));
99
+
100
+ pool->continuum = continuum;
101
+ pool->nserver_continuum = nserver_continuum;
102
+ /* pool->ncontinuum is initialized later as it could be <= ncontinuum */
103
+ }
104
+
105
+ /* update the continuum with the servers that are live */
106
+ continuum_index = 0;
107
+ pointer_counter = 0;
108
+ for (server_index = 0; server_index < nserver; server_index++) {
109
+ struct server *server = array_get(&pool->server, server_index);
110
+
111
+ if (pool->auto_eject_hosts && server->next_retry > now) {
112
+ continue;
113
+ }
114
+
115
+ pointer_per_server = 1;
116
+
117
+ pool->continuum[continuum_index].index = server_index;
118
+ pool->continuum[continuum_index++].value = 0;
119
+
120
+ pointer_counter += pointer_per_server;
121
+ }
122
+ pool->ncontinuum = pointer_counter;
123
+
124
+ log_debug(LOG_VERB, "updated pool %"PRIu32" '%.*s' with %"PRIu32" of "
125
+ "%"PRIu32" servers live in %"PRIu32" slots and %"PRIu32" "
126
+ "active points in %"PRIu32" slots", pool->idx,
127
+ pool->name.len, pool->name.data, nlive_server, nserver,
128
+ pool->nserver_continuum, pool->ncontinuum,
129
+ (pool->nserver_continuum + continuum_addition) * points_per_server);
130
+
131
+ return NC_OK;
132
+
133
+ }
134
+
135
+ uint32_t
136
+ random_dispatch(struct continuum *continuum, uint32_t ncontinuum, uint32_t hash)
137
+ {
138
+ struct continuum *c;
139
+
140
+ ASSERT(continuum != NULL);
141
+ ASSERT(ncontinuum != 0);
142
+
143
+ c = continuum + random() % ncontinuum;
144
+
145
+ return c->index;
146
+ }
@@ -0,0 +1,573 @@
1
+ /*
2
+ * twemproxy - A fast and lightweight proxy for memcached protocol.
3
+ * Copyright (C) 2011 Twitter, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include <stdio.h>
19
+ #include <stdlib.h>
20
+ #include <unistd.h>
21
+ #include <signal.h>
22
+ #include <getopt.h>
23
+ #include <fcntl.h>
24
+ #include <sys/stat.h>
25
+
26
+ #include <nc_core.h>
27
+ #include <nc_conf.h>
28
+ #include <nc_signal.h>
29
+
30
+ #define NC_CONF_PATH "conf/nutcracker.yml"
31
+
32
+ #define NC_LOG_DEFAULT LOG_NOTICE
33
+ #define NC_LOG_MIN LOG_EMERG
34
+ #define NC_LOG_MAX LOG_PVERB
35
+ #define NC_LOG_PATH NULL
36
+
37
+ #define NC_STATS_PORT STATS_PORT
38
+ #define NC_STATS_ADDR STATS_ADDR
39
+ #define NC_STATS_INTERVAL STATS_INTERVAL
40
+
41
+ #define NC_PID_FILE NULL
42
+
43
+ #define NC_MBUF_SIZE MBUF_SIZE
44
+ #define NC_MBUF_MIN_SIZE MBUF_MIN_SIZE
45
+ #define NC_MBUF_MAX_SIZE MBUF_MAX_SIZE
46
+
47
+ static int show_help;
48
+ static int show_version;
49
+ static int test_conf;
50
+ static int daemonize;
51
+ static int describe_stats;
52
+
53
+ static struct option long_options[] = {
54
+ { "help", no_argument, NULL, 'h' },
55
+ { "version", no_argument, NULL, 'V' },
56
+ { "test-conf", no_argument, NULL, 't' },
57
+ { "daemonize", no_argument, NULL, 'd' },
58
+ { "describe-stats", no_argument, NULL, 'D' },
59
+ { "verbose", required_argument, NULL, 'v' },
60
+ { "output", required_argument, NULL, 'o' },
61
+ { "conf-file", required_argument, NULL, 'c' },
62
+ { "stats-port", required_argument, NULL, 's' },
63
+ { "stats-interval", required_argument, NULL, 'i' },
64
+ { "stats-addr", required_argument, NULL, 'a' },
65
+ { "pid-file", required_argument, NULL, 'p' },
66
+ { "mbuf-size", required_argument, NULL, 'm' },
67
+ { NULL, 0, NULL, 0 }
68
+ };
69
+
70
+ static char short_options[] = "hVtdDv:o:c:s:i:a:p:m:";
71
+
72
+ static rstatus_t
73
+ nc_daemonize(int dump_core)
74
+ {
75
+ rstatus_t status;
76
+ pid_t pid, sid;
77
+ int fd;
78
+
79
+ pid = fork();
80
+ switch (pid) {
81
+ case -1:
82
+ log_error("fork() failed: %s", strerror(errno));
83
+ return NC_ERROR;
84
+
85
+ case 0:
86
+ break;
87
+
88
+ default:
89
+ /* parent terminates */
90
+ _exit(0);
91
+ }
92
+
93
+ /* 1st child continues and becomes the session leader */
94
+
95
+ sid = setsid();
96
+ if (sid < 0) {
97
+ log_error("setsid() failed: %s", strerror(errno));
98
+ return NC_ERROR;
99
+ }
100
+
101
+ if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
102
+ log_error("signal(SIGHUP, SIG_IGN) failed: %s", strerror(errno));
103
+ return NC_ERROR;
104
+ }
105
+
106
+ pid = fork();
107
+ switch (pid) {
108
+ case -1:
109
+ log_error("fork() failed: %s", strerror(errno));
110
+ return NC_ERROR;
111
+
112
+ case 0:
113
+ break;
114
+
115
+ default:
116
+ /* 1st child terminates */
117
+ _exit(0);
118
+ }
119
+
120
+ /* 2nd child continues */
121
+
122
+ /* change working directory */
123
+ if (dump_core == 0) {
124
+ status = chdir("/");
125
+ if (status < 0) {
126
+ log_error("chdir(\"/\") failed: %s", strerror(errno));
127
+ return NC_ERROR;
128
+ }
129
+ }
130
+
131
+ /* clear file mode creation mask */
132
+ umask(0);
133
+
134
+ /* redirect stdin, stdout and stderr to "/dev/null" */
135
+
136
+ fd = open("/dev/null", O_RDWR);
137
+ if (fd < 0) {
138
+ log_error("open(\"/dev/null\") failed: %s", strerror(errno));
139
+ return NC_ERROR;
140
+ }
141
+
142
+ status = dup2(fd, STDIN_FILENO);
143
+ if (status < 0) {
144
+ log_error("dup2(%d, STDIN) failed: %s", fd, strerror(errno));
145
+ close(fd);
146
+ return NC_ERROR;
147
+ }
148
+
149
+ status = dup2(fd, STDOUT_FILENO);
150
+ if (status < 0) {
151
+ log_error("dup2(%d, STDOUT) failed: %s", fd, strerror(errno));
152
+ close(fd);
153
+ return NC_ERROR;
154
+ }
155
+
156
+ status = dup2(fd, STDERR_FILENO);
157
+ if (status < 0) {
158
+ log_error("dup2(%d, STDERR) failed: %s", fd, strerror(errno));
159
+ close(fd);
160
+ return NC_ERROR;
161
+ }
162
+
163
+ if (fd > STDERR_FILENO) {
164
+ status = close(fd);
165
+ if (status < 0) {
166
+ log_error("close(%d) failed: %s", fd, strerror(errno));
167
+ return NC_ERROR;
168
+ }
169
+ }
170
+
171
+ return NC_OK;
172
+ }
173
+
174
+ static void
175
+ nc_print_run(struct instance *nci)
176
+ {
177
+ loga("nutcracker-%s started on pid %d", NC_VERSION_STRING, nci->pid);
178
+
179
+ loga("run, rabbit run / dig that hole, forget the sun / "
180
+ "and when at last the work is done / don't sit down / "
181
+ "it's time to dig another one");
182
+ }
183
+
184
+ static void
185
+ nc_print_done(void)
186
+ {
187
+ loga("done, rabbit done");
188
+ }
189
+
190
+ static void
191
+ nc_show_usage(void)
192
+ {
193
+ log_stderr(
194
+ "Usage: nutcracker [-?hVdDt] [-v verbosity level] [-o output file]" CRLF
195
+ " [-c conf file] [-s stats port] [-a stats addr]" CRLF
196
+ " [-i stats interval] [-p pid file] [-m mbuf size]" CRLF
197
+ "");
198
+ log_stderr(
199
+ "Options:" CRLF
200
+ " -h, --help : this help" CRLF
201
+ " -V, --version : show version and exit" CRLF
202
+ " -t, --test-conf : test configuration for syntax errors and exit" CRLF
203
+ " -d, --daemonize : run as a daemon" CRLF
204
+ " -D, --describe-stats : print stats description and exit");
205
+ log_stderr(
206
+ " -v, --verbosity=N : set logging level (default: %d, min: %d, max: %d)" CRLF
207
+ " -o, --output=S : set logging file (default: %s)" CRLF
208
+ " -c, --conf-file=S : set configuration file (default: %s)" CRLF
209
+ " -s, --stats-port=N : set stats monitoring port (default: %d)" CRLF
210
+ " -a, --stats-addr=S : set stats monitoring ip (default: %s)" CRLF
211
+ " -i, --stats-interval=N : set stats aggregation interval in msec (default: %d msec)" CRLF
212
+ " -p, --pid-file=S : set pid file (default: %s)" CRLF
213
+ " -m, --mbuf-size=N : set size of mbuf chunk in bytes (default: %d bytes)" CRLF
214
+ "",
215
+ NC_LOG_DEFAULT, NC_LOG_MIN, NC_LOG_MAX,
216
+ NC_LOG_PATH != NULL ? NC_LOG_PATH : "stderr",
217
+ NC_CONF_PATH,
218
+ NC_STATS_PORT, NC_STATS_ADDR, NC_STATS_INTERVAL,
219
+ NC_PID_FILE != NULL ? NC_PID_FILE : "off",
220
+ NC_MBUF_SIZE);
221
+ }
222
+
223
+ static rstatus_t
224
+ nc_create_pidfile(struct instance *nci)
225
+ {
226
+ char pid[NC_UINTMAX_MAXLEN];
227
+ int fd, pid_len;
228
+ ssize_t n;
229
+
230
+ fd = open(nci->pid_filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
231
+ if (fd < 0) {
232
+ log_error("opening pid file '%s' failed: %s", nci->pid_filename,
233
+ strerror(errno));
234
+ return NC_ERROR;
235
+ }
236
+ nci->pidfile = 1;
237
+
238
+ pid_len = nc_snprintf(pid, NC_UINTMAX_MAXLEN, "%d", nci->pid);
239
+
240
+ n = nc_write(fd, pid, pid_len);
241
+ if (n < 0) {
242
+ log_error("write to pid file '%s' failed: %s", nci->pid_filename,
243
+ strerror(errno));
244
+ return NC_ERROR;
245
+ }
246
+
247
+ close(fd);
248
+
249
+ return NC_OK;
250
+ }
251
+
252
+ static void
253
+ nc_remove_pidfile(struct instance *nci)
254
+ {
255
+ int status;
256
+
257
+ status = unlink(nci->pid_filename);
258
+ if (status < 0) {
259
+ log_error("unlink of pid file '%s' failed, ignored: %s",
260
+ nci->pid_filename, strerror(errno));
261
+ }
262
+ }
263
+
264
+ static void
265
+ nc_set_default_options(struct instance *nci)
266
+ {
267
+ int status;
268
+
269
+ nci->ctx = NULL;
270
+
271
+ nci->log_level = NC_LOG_DEFAULT;
272
+ nci->log_filename = NC_LOG_PATH;
273
+
274
+ nci->conf_filename = NC_CONF_PATH;
275
+
276
+ nci->stats_port = NC_STATS_PORT;
277
+ nci->stats_addr = NC_STATS_ADDR;
278
+ nci->stats_interval = NC_STATS_INTERVAL;
279
+
280
+ status = nc_gethostname(nci->hostname, NC_MAXHOSTNAMELEN);
281
+ if (status < 0) {
282
+ log_warn("gethostname failed, ignored: %s", strerror(errno));
283
+ nc_snprintf(nci->hostname, NC_MAXHOSTNAMELEN, "unknown");
284
+ }
285
+ nci->hostname[NC_MAXHOSTNAMELEN - 1] = '\0';
286
+
287
+ nci->mbuf_chunk_size = NC_MBUF_SIZE;
288
+
289
+ nci->pid = (pid_t)-1;
290
+ nci->pid_filename = NULL;
291
+ nci->pidfile = 0;
292
+ }
293
+
294
+ static rstatus_t
295
+ nc_get_options(int argc, char **argv, struct instance *nci)
296
+ {
297
+ int c, value;
298
+
299
+ opterr = 0;
300
+
301
+ for (;;) {
302
+ c = getopt_long(argc, argv, short_options, long_options, NULL);
303
+ if (c == -1) {
304
+ /* no more options */
305
+ break;
306
+ }
307
+
308
+ switch (c) {
309
+ case 'h':
310
+ show_version = 1;
311
+ show_help = 1;
312
+ break;
313
+
314
+ case 'V':
315
+ show_version = 1;
316
+ break;
317
+
318
+ case 't':
319
+ test_conf = 1;
320
+ break;
321
+
322
+ case 'd':
323
+ daemonize = 1;
324
+ break;
325
+
326
+ case 'D':
327
+ describe_stats = 1;
328
+ show_version = 1;
329
+ break;
330
+
331
+ case 'v':
332
+ value = nc_atoi(optarg, strlen(optarg));
333
+ if (value < 0) {
334
+ log_stderr("nutcracker: option -v requires a number");
335
+ return NC_ERROR;
336
+ }
337
+ nci->log_level = value;
338
+ break;
339
+
340
+ case 'o':
341
+ nci->log_filename = optarg;
342
+ break;
343
+
344
+ case 'c':
345
+ nci->conf_filename = optarg;
346
+ break;
347
+
348
+ case 's':
349
+ value = nc_atoi(optarg, strlen(optarg));
350
+ if (value < 0) {
351
+ log_stderr("nutcracker: option -s requires a number");
352
+ return NC_ERROR;
353
+ }
354
+ if (!nc_valid_port(value)) {
355
+ log_stderr("nutcracker: option -s value %d is not a valid "
356
+ "port", value);
357
+ return NC_ERROR;
358
+ }
359
+
360
+ nci->stats_port = (uint16_t)value;
361
+ break;
362
+
363
+ case 'i':
364
+ value = nc_atoi(optarg, strlen(optarg));
365
+ if (value < 0) {
366
+ log_stderr("nutcracker: option -i requires a number");
367
+ return NC_ERROR;
368
+ }
369
+
370
+ nci->stats_interval = value;
371
+ break;
372
+
373
+ case 'a':
374
+ nci->stats_addr = optarg;
375
+ break;
376
+
377
+ case 'p':
378
+ nci->pid_filename = optarg;
379
+ break;
380
+
381
+ case 'm':
382
+ value = nc_atoi(optarg, strlen(optarg));
383
+ if (value <= 0) {
384
+ log_stderr("nutcracker: option -m requires a non-zero number");
385
+ return NC_ERROR;
386
+ }
387
+
388
+ if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) {
389
+ log_stderr("nutcracker: mbuf chunk size must be between %zu and"
390
+ " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE);
391
+ return NC_ERROR;
392
+ }
393
+
394
+ nci->mbuf_chunk_size = (size_t)value;
395
+ break;
396
+
397
+ case '?':
398
+ switch (optopt) {
399
+ case 'o':
400
+ case 'c':
401
+ case 'p':
402
+ log_stderr("nutcracker: option -%c requires a file name",
403
+ optopt);
404
+ break;
405
+
406
+ case 'm':
407
+ case 'v':
408
+ case 's':
409
+ case 'i':
410
+ log_stderr("nutcracker: option -%c requires a number", optopt);
411
+ break;
412
+
413
+ case 'a':
414
+ log_stderr("nutcracker: option -%c requires a string", optopt);
415
+ break;
416
+
417
+ default:
418
+ log_stderr("nutcracker: invalid option -- '%c'", optopt);
419
+ break;
420
+ }
421
+ return NC_ERROR;
422
+
423
+ default:
424
+ log_stderr("nutcracker: invalid option -- '%c'", optopt);
425
+ return NC_ERROR;
426
+
427
+ }
428
+ }
429
+
430
+ return NC_OK;
431
+ }
432
+
433
+ /*
434
+ * Returns true if configuration file has a valid syntax, otherwise
435
+ * returns false
436
+ */
437
+ static bool
438
+ nc_test_conf(struct instance *nci)
439
+ {
440
+ struct conf *cf;
441
+
442
+ cf = conf_create(nci->conf_filename);
443
+ if (cf == NULL) {
444
+ log_stderr("nutcracker: configuration file '%s' syntax is invalid",
445
+ nci->conf_filename);
446
+ return false;
447
+ }
448
+
449
+ conf_destroy(cf);
450
+
451
+ log_stderr("nutcracker: configuration file '%s' syntax is ok",
452
+ nci->conf_filename);
453
+ return true;
454
+ }
455
+
456
+ static rstatus_t
457
+ nc_pre_run(struct instance *nci)
458
+ {
459
+ rstatus_t status;
460
+
461
+ status = log_init(nci->log_level, nci->log_filename);
462
+ if (status != NC_OK) {
463
+ return status;
464
+ }
465
+
466
+ if (daemonize) {
467
+ status = nc_daemonize(1);
468
+ if (status != NC_OK) {
469
+ return status;
470
+ }
471
+ }
472
+
473
+ nci->pid = getpid();
474
+
475
+ status = signal_init();
476
+ if (status != NC_OK) {
477
+ return status;
478
+ }
479
+
480
+ if (nci->pid_filename) {
481
+ status = nc_create_pidfile(nci);
482
+ if (status != NC_OK) {
483
+ return status;
484
+ }
485
+ }
486
+
487
+ nc_print_run(nci);
488
+
489
+ return NC_OK;
490
+ }
491
+
492
+ static void
493
+ nc_post_run(struct instance *nci)
494
+ {
495
+ if (nci->pidfile) {
496
+ nc_remove_pidfile(nci);
497
+ }
498
+
499
+ signal_deinit();
500
+
501
+ nc_print_done();
502
+
503
+ log_deinit();
504
+ }
505
+
506
+ static void
507
+ nc_run(struct instance *nci)
508
+ {
509
+ rstatus_t status;
510
+ struct context *ctx;
511
+
512
+ ctx = core_start(nci);
513
+ if (ctx == NULL) {
514
+ return;
515
+ }
516
+
517
+ /* run rabbit run */
518
+ for (;;) {
519
+ status = core_loop(ctx);
520
+ if (status != NC_OK) {
521
+ break;
522
+ }
523
+ }
524
+
525
+ core_stop(ctx);
526
+ }
527
+
528
+ int
529
+ main(int argc, char **argv)
530
+ {
531
+ rstatus_t status;
532
+ struct instance nci;
533
+
534
+ nc_set_default_options(&nci);
535
+
536
+ status = nc_get_options(argc, argv, &nci);
537
+ if (status != NC_OK) {
538
+ nc_show_usage();
539
+ exit(1);
540
+ }
541
+
542
+ if (show_version) {
543
+ log_stderr("This is nutcracker-%s" CRLF, NC_VERSION_STRING);
544
+ if (show_help) {
545
+ nc_show_usage();
546
+ }
547
+
548
+ if (describe_stats) {
549
+ stats_describe();
550
+ }
551
+
552
+ exit(0);
553
+ }
554
+
555
+ if (test_conf) {
556
+ if (!nc_test_conf(&nci)) {
557
+ exit(1);
558
+ }
559
+ exit(0);
560
+ }
561
+
562
+ status = nc_pre_run(&nci);
563
+ if (status != NC_OK) {
564
+ nc_post_run(&nci);
565
+ exit(1);
566
+ }
567
+
568
+ nc_run(&nci);
569
+
570
+ nc_post_run(&nci);
571
+
572
+ exit(1);
573
+ }