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.
- data/README.md +22 -0
- data/Rakefile +55 -0
- data/bin/nutcracker +2 -0
- data/ext/nutcracker/ChangeLog +66 -0
- data/ext/nutcracker/LICENSE +177 -0
- data/ext/nutcracker/Makefile.am +7 -0
- data/ext/nutcracker/Makefile.in +726 -0
- data/ext/nutcracker/NOTICE +124 -0
- data/ext/nutcracker/README.md +240 -0
- data/ext/nutcracker/aclocal.m4 +956 -0
- data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
- data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
- data/ext/nutcracker/conf/nutcracker.yml +67 -0
- data/ext/nutcracker/config.h.in +316 -0
- data/ext/nutcracker/config/config.guess +1561 -0
- data/ext/nutcracker/config/config.sub +1686 -0
- data/ext/nutcracker/config/depcomp +630 -0
- data/ext/nutcracker/config/install-sh +520 -0
- data/ext/nutcracker/config/ltmain.sh +8413 -0
- data/ext/nutcracker/config/missing +376 -0
- data/ext/nutcracker/configure +18862 -0
- data/ext/nutcracker/configure.ac +155 -0
- data/ext/nutcracker/contrib/Makefile.am +3 -0
- data/ext/nutcracker/contrib/Makefile.in +560 -0
- data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
- data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
- data/ext/nutcracker/extconf.rb +5 -0
- data/ext/nutcracker/m4/libtool.m4 +7376 -0
- data/ext/nutcracker/m4/ltoptions.m4 +368 -0
- data/ext/nutcracker/m4/ltsugar.m4 +123 -0
- data/ext/nutcracker/m4/ltversion.m4 +23 -0
- data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
- data/ext/nutcracker/notes/c-styleguide.txt +425 -0
- data/ext/nutcracker/notes/debug.txt +96 -0
- data/ext/nutcracker/notes/memcache.txt +123 -0
- data/ext/nutcracker/notes/recommendation.md +118 -0
- data/ext/nutcracker/notes/redis.md +415 -0
- data/ext/nutcracker/notes/socket.txt +131 -0
- data/ext/nutcracker/scripts/multi_get.sh +26 -0
- data/ext/nutcracker/scripts/nutcracker.init +73 -0
- data/ext/nutcracker/scripts/nutcracker.spec +52 -0
- data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
- data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
- data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
- data/ext/nutcracker/scripts/redis-check.py +23 -0
- data/ext/nutcracker/scripts/redis-check.sh +564 -0
- data/ext/nutcracker/src/Makefile.am +46 -0
- data/ext/nutcracker/src/Makefile.in +726 -0
- data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
- data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
- data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
- data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
- data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
- data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
- data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
- data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
- data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
- data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
- data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
- data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
- data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
- data/ext/nutcracker/src/nc.c +573 -0
- data/ext/nutcracker/src/nc_array.c +204 -0
- data/ext/nutcracker/src/nc_array.h +73 -0
- data/ext/nutcracker/src/nc_client.c +189 -0
- data/ext/nutcracker/src/nc_client.h +28 -0
- data/ext/nutcracker/src/nc_conf.c +1766 -0
- data/ext/nutcracker/src/nc_conf.h +134 -0
- data/ext/nutcracker/src/nc_connection.c +392 -0
- data/ext/nutcracker/src/nc_connection.h +99 -0
- data/ext/nutcracker/src/nc_core.c +334 -0
- data/ext/nutcracker/src/nc_core.h +131 -0
- data/ext/nutcracker/src/nc_event.c +214 -0
- data/ext/nutcracker/src/nc_event.h +39 -0
- data/ext/nutcracker/src/nc_log.c +254 -0
- data/ext/nutcracker/src/nc_log.h +120 -0
- data/ext/nutcracker/src/nc_mbuf.c +285 -0
- data/ext/nutcracker/src/nc_mbuf.h +67 -0
- data/ext/nutcracker/src/nc_message.c +828 -0
- data/ext/nutcracker/src/nc_message.h +253 -0
- data/ext/nutcracker/src/nc_proxy.c +359 -0
- data/ext/nutcracker/src/nc_proxy.h +34 -0
- data/ext/nutcracker/src/nc_queue.h +788 -0
- data/ext/nutcracker/src/nc_rbtree.c +348 -0
- data/ext/nutcracker/src/nc_rbtree.h +47 -0
- data/ext/nutcracker/src/nc_request.c +588 -0
- data/ext/nutcracker/src/nc_response.c +332 -0
- data/ext/nutcracker/src/nc_server.c +841 -0
- data/ext/nutcracker/src/nc_server.h +143 -0
- data/ext/nutcracker/src/nc_signal.c +131 -0
- data/ext/nutcracker/src/nc_signal.h +34 -0
- data/ext/nutcracker/src/nc_stats.c +1188 -0
- data/ext/nutcracker/src/nc_stats.h +206 -0
- data/ext/nutcracker/src/nc_string.c +109 -0
- data/ext/nutcracker/src/nc_string.h +112 -0
- data/ext/nutcracker/src/nc_util.c +619 -0
- data/ext/nutcracker/src/nc_util.h +214 -0
- data/ext/nutcracker/src/proto/Makefile.am +14 -0
- data/ext/nutcracker/src/proto/Makefile.in +482 -0
- data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
- data/ext/nutcracker/src/proto/nc_proto.h +155 -0
- data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
- data/lib/nutcracker.rb +7 -0
- data/lib/nutcracker/version.rb +3 -0
- 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
|
+
}
|