nutcracker 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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
+ }