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,206 @@
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
+ #ifndef _NC_STATS_H_
19
+ #define _NC_STATS_H_
20
+
21
+ #include <sys/epoll.h>
22
+
23
+ #include <nc_core.h>
24
+
25
+ #define STATS_POOL_CODEC(ACTION) \
26
+ /* client behavior */ \
27
+ ACTION( client_eof, STATS_COUNTER, "# eof on client connections") \
28
+ ACTION( client_err, STATS_COUNTER, "# errors on client connections") \
29
+ ACTION( client_connections, STATS_GAUGE, "# active client connections") \
30
+ /* pool behavior */ \
31
+ ACTION( server_ejects, STATS_COUNTER, "# times backend server was ejected") \
32
+ /* forwarder behavior */ \
33
+ ACTION( forward_error, STATS_COUNTER, "# times we encountered a forwarding error") \
34
+ ACTION( fragments, STATS_COUNTER, "# fragments created from a multi-vector request") \
35
+
36
+ #define STATS_SERVER_CODEC(ACTION) \
37
+ /* server behavior */ \
38
+ ACTION( server_eof, STATS_COUNTER, "# eof on server connections") \
39
+ ACTION( server_err, STATS_COUNTER, "# errors on server connections") \
40
+ ACTION( server_timedout, STATS_COUNTER, "# timeouts on server connections") \
41
+ ACTION( server_connections, STATS_GAUGE, "# active server connections") \
42
+ /* data behavior */ \
43
+ ACTION( requests, STATS_COUNTER, "# requests") \
44
+ ACTION( request_bytes, STATS_COUNTER, "total request bytes") \
45
+ ACTION( responses, STATS_COUNTER, "# respones") \
46
+ ACTION( response_bytes, STATS_COUNTER, "total response bytes") \
47
+ ACTION( in_queue, STATS_GAUGE, "# requests in incoming queue") \
48
+ ACTION( in_queue_bytes, STATS_GAUGE, "current request bytes in incoming queue") \
49
+ ACTION( out_queue, STATS_GAUGE, "# requests in outgoing queue") \
50
+ ACTION( out_queue_bytes, STATS_GAUGE, "current request bytes in outgoing queue") \
51
+
52
+ #define STATS_ADDR "0.0.0.0"
53
+ #define STATS_PORT 22222
54
+ #define STATS_INTERVAL (30 * 1000) /* in msec */
55
+
56
+ typedef enum stats_type {
57
+ STATS_INVALID,
58
+ STATS_COUNTER, /* monotonic accumulator */
59
+ STATS_GAUGE, /* non-monotonic accumulator */
60
+ STATS_TIMESTAMP, /* monotonic timestamp (in nsec) */
61
+ STATS_SENTINEL
62
+ } stats_type_t;
63
+
64
+ struct stats_metric {
65
+ stats_type_t type; /* type */
66
+ struct string name; /* name (ref) */
67
+ union {
68
+ int64_t counter; /* accumulating counter */
69
+ int64_t timestamp; /* monotonic timestamp */
70
+ } value;
71
+ };
72
+
73
+ struct stats_server {
74
+ struct string name; /* server name (ref) */
75
+ struct array metric; /* stats_metric[] for server codec */
76
+ };
77
+
78
+ struct stats_pool {
79
+ struct string name; /* pool name (ref) */
80
+ struct array metric; /* stats_metric[] for pool codec */
81
+ struct array server; /* stats_server[] */
82
+ };
83
+
84
+ struct stats_buffer {
85
+ size_t len; /* buffer length */
86
+ uint8_t *data; /* buffer data */
87
+ size_t size; /* buffer alloc size */
88
+ };
89
+
90
+ struct stats {
91
+ uint16_t port; /* stats monitoring port */
92
+ int interval; /* stats aggregation interval */
93
+ struct string addr; /* stats monitoring address */
94
+
95
+ int64_t start_ts; /* start timestamp of nutcracker */
96
+ struct stats_buffer buf; /* output buffer */
97
+
98
+ struct array current; /* stats_pool[] (a) */
99
+ struct array shadow; /* stats_pool[] (b) */
100
+ struct array sum; /* stats_pool[] (c = a + b) */
101
+
102
+ pthread_t tid; /* stats aggregator thread */
103
+ int sd; /* stats descriptor */
104
+ int ep; /* epoll device */
105
+ struct epoll_event event; /* epoll event */
106
+
107
+ struct string service_str; /* service string */
108
+ struct string service; /* service */
109
+ struct string source_str; /* source string */
110
+ struct string source; /* source */
111
+ struct string version_str; /* version string */
112
+ struct string version; /* version */
113
+ struct string uptime_str; /* uptime string */
114
+ struct string timestamp_str; /* timestamp string */
115
+
116
+ volatile int aggregate; /* shadow (b) aggregate? */
117
+ volatile int updated; /* current (a) updated? */
118
+ };
119
+
120
+ #define DEFINE_ACTION(_name, _type, _desc) STATS_POOL_##_name,
121
+ typedef enum stats_pool_field {
122
+ STATS_POOL_CODEC(DEFINE_ACTION)
123
+ STATS_POOL_NFIELD
124
+ } stats_pool_field_t;
125
+ #undef DEFINE_ACTION
126
+
127
+ #define DEFINE_ACTION(_name, _type, _desc) STATS_SERVER_##_name,
128
+ typedef enum stats_server_field {
129
+ STATS_SERVER_CODEC(DEFINE_ACTION)
130
+ STATS_SERVER_NFIELD
131
+ } stats_server_field_t;
132
+ #undef DEFINE_ACTION
133
+
134
+ #if defined NC_STATS && NC_STATS == 1
135
+
136
+ #define stats_pool_incr(_ctx, _pool, _name) do { \
137
+ _stats_pool_incr(_ctx, _pool, STATS_POOL_##_name); \
138
+ } while (0)
139
+
140
+ #define stats_pool_decr(_ctx, _pool, _name) do { \
141
+ _stats_pool_decr(_ctx, _pool, STATS_POOL_##_name); \
142
+ } while (0)
143
+
144
+ #define stats_pool_incr_by(_ctx, _pool, _name, _val) do { \
145
+ _stats_pool_incr_by(_ctx, _pool, STATS_POOL_##_name, _val); \
146
+ } while (0)
147
+
148
+ #define stats_pool_decr_by(_ctx, _pool, _name, _val) do { \
149
+ _stats_pool_decr_by(_ctx, _pool, STATS_POOL_##_name, _val); \
150
+ } while (0)
151
+
152
+ #define stats_server_incr(_ctx, _server, _name) do { \
153
+ _stats_server_incr(_ctx, _server, STATS_SERVER_##_name); \
154
+ } while (0)
155
+
156
+ #define stats_server_decr(_ctx, _server, _name) do { \
157
+ _stats_server_decr(_ctx, _server, STATS_SERVER_##_name); \
158
+ } while (0)
159
+
160
+ #define stats_server_incr_by(_ctx, _server, _name, _val) do { \
161
+ _stats_server_incr_by(_ctx, _server, STATS_SERVER_##_name, _val); \
162
+ } while (0)
163
+
164
+ #define stats_server_decr_by(_ctx, _server, _name, _val) do { \
165
+ _stats_server_decr_by(_ctx, _server, STATS_SERVER_##_name, _val); \
166
+ } while (0)
167
+
168
+ #else
169
+
170
+ #define stats_pool_incr(_ctx, _pool, _name)
171
+
172
+ #define stats_pool_decr(_ctx, _pool, _name)
173
+
174
+ #define stats_pool_incr_by(_ctx, _pool, _name, _val)
175
+
176
+ #define stats_pool_decr_by(_ctx, _pool, _name, _val)
177
+
178
+ #define stats_server_incr(_ctx, _server, _name)
179
+
180
+ #define stats_server_decr(_ctx, _server, _name)
181
+
182
+ #define stats_server_incr_by(_ctx, _server, _name, _val)
183
+
184
+ #define stats_server_decr_by(_ctx, _server, _name, _val)
185
+
186
+ #endif
187
+
188
+ #define stats_enabled NC_STATS
189
+
190
+ void stats_describe(void);
191
+
192
+ void _stats_pool_incr(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx);
193
+ void _stats_pool_decr(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx);
194
+ void _stats_pool_incr_by(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx, int64_t val);
195
+ void _stats_pool_decr_by(struct context *ctx, struct server_pool *pool, stats_pool_field_t fidx, int64_t val);
196
+
197
+ void _stats_server_incr(struct context *ctx, struct server *server, stats_server_field_t fidx);
198
+ void _stats_server_decr(struct context *ctx, struct server *server, stats_server_field_t fidx);
199
+ void _stats_server_incr_by(struct context *ctx, struct server *server, stats_server_field_t fidx, int64_t val);
200
+ void _stats_server_decr_by(struct context *ctx, struct server *server, stats_server_field_t fidx, int64_t val);
201
+
202
+ struct stats *stats_create(uint16_t stats_port, char *stats_ip, int stats_interval, char *source, struct array *server_pool);
203
+ void stats_destroy(struct stats *stats);
204
+ void stats_swap(struct stats *stats);
205
+
206
+ #endif
@@ -0,0 +1,109 @@
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 <stdlib.h>
19
+ #include <string.h>
20
+
21
+ #include <nc_core.h>
22
+
23
+ /*
24
+ * String (struct string) is a sequence of unsigned char objects terminated
25
+ * by the null character '\0'. The length of the string is pre-computed and
26
+ * made available explicitly as an additional field. This means that we don't
27
+ * have to walk the entire character sequence until the null terminating
28
+ * character everytime that the length of the String is requested
29
+ *
30
+ * The only way to create a String is to initialize it using, string_init()
31
+ * and duplicate an existing String - string_duplicate() or copy an existing
32
+ * raw sequence of character bytes - string_copy(). Such String's must be
33
+ * freed using string_deinit()
34
+ *
35
+ * We can also create String as reference to raw string - string_set_raw()
36
+ * or to text string - string_set_text() or string(). Such String don't have
37
+ * to be freed.
38
+ */
39
+
40
+ void
41
+ string_init(struct string *str)
42
+ {
43
+ str->len = 0;
44
+ str->data = NULL;
45
+ }
46
+
47
+ void
48
+ string_deinit(struct string *str)
49
+ {
50
+ ASSERT((str->len == 0 && str->data == NULL) ||
51
+ (str->len != 0 && str->data != NULL));
52
+
53
+ if (str->data != NULL) {
54
+ nc_free(str->data);
55
+ string_init(str);
56
+ }
57
+ }
58
+
59
+ bool
60
+ string_empty(const struct string *str)
61
+ {
62
+ ASSERT((str->len == 0 && str->data == NULL) ||
63
+ (str->len != 0 && str->data != NULL));
64
+ return str->len == 0 ? true : false;
65
+ }
66
+
67
+ rstatus_t
68
+ string_duplicate(struct string *dst, const struct string *src)
69
+ {
70
+ ASSERT(dst->len == 0 && dst->data == NULL);
71
+ ASSERT(src->len != 0 && src->data != NULL);
72
+
73
+ dst->data = nc_strndup(src->data, src->len + 1);
74
+ if (dst->data == NULL) {
75
+ return NC_ENOMEM;
76
+ }
77
+
78
+ dst->len = src->len;
79
+ dst->data[dst->len] = '\0';
80
+
81
+ return NC_OK;
82
+ }
83
+
84
+ rstatus_t
85
+ string_copy(struct string *dst, const uint8_t *src, uint32_t srclen)
86
+ {
87
+ ASSERT(dst->len == 0 && dst->data == NULL);
88
+ ASSERT(src != NULL && srclen != 0);
89
+
90
+ dst->data = nc_strndup(src, srclen + 1);
91
+ if (dst->data == NULL) {
92
+ return NC_ENOMEM;
93
+ }
94
+
95
+ dst->len = srclen;
96
+ dst->data[dst->len] = '\0';
97
+
98
+ return NC_OK;
99
+ }
100
+
101
+ int
102
+ string_compare(const struct string *s1, const struct string *s2)
103
+ {
104
+ if (s1->len != s2->len) {
105
+ return s1->len - s2->len > 0 ? 1 : -1;
106
+ }
107
+
108
+ return nc_strncmp(s1->data, s2->data, s1->len);
109
+ }
@@ -0,0 +1,112 @@
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
+ #ifndef _NC_STRING_H_
19
+ #define _NC_STRING_H_
20
+
21
+ #include <string.h>
22
+ #include <nc_core.h>
23
+
24
+ struct string {
25
+ uint32_t len; /* string length */
26
+ uint8_t *data; /* string data */
27
+ };
28
+
29
+ #define string(_str) { sizeof(_str) - 1, (uint8_t *)(_str) }
30
+ #define null_string { 0, NULL }
31
+
32
+ #define string_set_text(_str, _text) do { \
33
+ (_str)->len = (uint32_t)(sizeof(_text) - 1);\
34
+ (_str)->data = (uint8_t *)(_text); \
35
+ } while (0);
36
+
37
+ #define string_set_raw(_str, _raw) do { \
38
+ (_str)->len = (uint32_t)(nc_strlen(_raw)); \
39
+ (_str)->data = (uint8_t *)(_raw); \
40
+ } while (0);
41
+
42
+ void string_init(struct string *str);
43
+ void string_deinit(struct string *str);
44
+ bool string_empty(const struct string *str);
45
+ rstatus_t string_duplicate(struct string *dst, const struct string *src);
46
+ rstatus_t string_copy(struct string *dst, const uint8_t *src, uint32_t srclen);
47
+ int string_compare(const struct string *s1, const struct string *s2);
48
+
49
+ /*
50
+ * Wrapper around common routines for manipulating C character
51
+ * strings
52
+ */
53
+ #define nc_memcpy(_d, _c, _n) \
54
+ memcpy(_d, _c, (size_t)(_n))
55
+
56
+ #define nc_memmove(_d, _c, _n) \
57
+ memmove(_d, _c, (size_t)(_n))
58
+
59
+ #define nc_memchr(_d, _c, _n) \
60
+ memchr(_d, _c, (size_t)(_n))
61
+
62
+ #define nc_strlen(_s) \
63
+ strlen((char *)(_s))
64
+
65
+ #define nc_strncmp(_s1, _s2, _n) \
66
+ strncmp((char *)(_s1), (char *)(_s2), (size_t)(_n))
67
+
68
+ #define nc_strchr(_p, _l, _c) \
69
+ _nc_strchr((uint8_t *)(_p), (uint8_t *)(_l), (uint8_t)(_c))
70
+
71
+ #define nc_strrchr(_p, _s, _c) \
72
+ _nc_strrchr((uint8_t *)(_p),(uint8_t *)(_s), (uint8_t)(_c))
73
+
74
+ #define nc_strndup(_s, _n) \
75
+ (uint8_t *)strndup((char *)(_s), (size_t)(_n));
76
+
77
+ #define nc_snprintf(_s, _n, ...) \
78
+ snprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
79
+
80
+ #define nc_scnprintf(_s, _n, ...) \
81
+ _scnprintf((char *)(_s), (size_t)(_n), __VA_ARGS__)
82
+
83
+ #define nc_vscnprintf(_s, _n, _f, _a) \
84
+ _vscnprintf((char *)(_s), (size_t)(_n), _f, _a)
85
+
86
+ static inline uint8_t *
87
+ _nc_strchr(uint8_t *p, uint8_t *last, uint8_t c)
88
+ {
89
+ while (p < last) {
90
+ if (*p == c) {
91
+ return p;
92
+ }
93
+ p++;
94
+ }
95
+
96
+ return NULL;
97
+ }
98
+
99
+ static inline uint8_t *
100
+ _nc_strrchr(uint8_t *p, uint8_t *start, uint8_t c)
101
+ {
102
+ while (p >= start) {
103
+ if (*p == c) {
104
+ return p;
105
+ }
106
+ p--;
107
+ }
108
+
109
+ return NULL;
110
+ }
111
+
112
+ #endif
@@ -0,0 +1,619 @@
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 <stdarg.h>
21
+ #include <string.h>
22
+ #include <unistd.h>
23
+ #include <fcntl.h>
24
+ #include <netdb.h>
25
+ #include <execinfo.h>
26
+
27
+ #include <sys/time.h>
28
+ #include <sys/types.h>
29
+ #include <sys/socket.h>
30
+ #include <sys/ioctl.h>
31
+
32
+ #include <netinet/in.h>
33
+ #include <netinet/tcp.h>
34
+
35
+ #include <nc_core.h>
36
+
37
+ int
38
+ nc_set_blocking(int sd)
39
+ {
40
+ int flags;
41
+
42
+ flags = fcntl(sd, F_GETFL, 0);
43
+ if (flags < 0) {
44
+ return flags;
45
+ }
46
+
47
+ return fcntl(sd, F_SETFL, flags & ~O_NONBLOCK);
48
+ }
49
+
50
+ int
51
+ nc_set_nonblocking(int sd)
52
+ {
53
+ int flags;
54
+
55
+ flags = fcntl(sd, F_GETFL, 0);
56
+ if (flags < 0) {
57
+ return flags;
58
+ }
59
+
60
+ return fcntl(sd, F_SETFL, flags | O_NONBLOCK);
61
+ }
62
+
63
+ int
64
+ nc_set_reuseaddr(int sd)
65
+ {
66
+ int reuse;
67
+ socklen_t len;
68
+
69
+ reuse = 1;
70
+ len = sizeof(reuse);
71
+
72
+ return setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, len);
73
+ }
74
+
75
+ /*
76
+ * Disable Nagle algorithm on TCP socket.
77
+ *
78
+ * This option helps to minimize transmit latency by disabling coalescing
79
+ * of data to fill up a TCP segment inside the kernel. Sockets with this
80
+ * option must use readv() or writev() to do data transfer in bulk and
81
+ * hence avoid the overhead of small packets.
82
+ */
83
+ int
84
+ nc_set_tcpnodelay(int sd)
85
+ {
86
+ int nodelay;
87
+ socklen_t len;
88
+
89
+ nodelay = 1;
90
+ len = sizeof(nodelay);
91
+
92
+ return setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len);
93
+ }
94
+
95
+ int
96
+ nc_set_linger(int sd, int timeout)
97
+ {
98
+ struct linger linger;
99
+ socklen_t len;
100
+
101
+ linger.l_onoff = 1;
102
+ linger.l_linger = timeout;
103
+
104
+ len = sizeof(linger);
105
+
106
+ return setsockopt(sd, SOL_SOCKET, SO_LINGER, &linger, len);
107
+ }
108
+
109
+ int
110
+ nc_set_sndbuf(int sd, int size)
111
+ {
112
+ socklen_t len;
113
+
114
+ len = sizeof(size);
115
+
116
+ return setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, len);
117
+ }
118
+
119
+ int
120
+ nc_set_rcvbuf(int sd, int size)
121
+ {
122
+ socklen_t len;
123
+
124
+ len = sizeof(size);
125
+
126
+ return setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, len);
127
+ }
128
+
129
+ int
130
+ nc_get_soerror(int sd)
131
+ {
132
+ int status, err;
133
+ socklen_t len;
134
+
135
+ err = 0;
136
+ len = sizeof(err);
137
+
138
+ status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len);
139
+ if (status == 0) {
140
+ errno = err;
141
+ }
142
+
143
+ return status;
144
+ }
145
+
146
+ int
147
+ nc_get_sndbuf(int sd)
148
+ {
149
+ int status, size;
150
+ socklen_t len;
151
+
152
+ size = 0;
153
+ len = sizeof(size);
154
+
155
+ status = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, &len);
156
+ if (status < 0) {
157
+ return status;
158
+ }
159
+
160
+ return size;
161
+ }
162
+
163
+ int
164
+ nc_get_rcvbuf(int sd)
165
+ {
166
+ int status, size;
167
+ socklen_t len;
168
+
169
+ size = 0;
170
+ len = sizeof(size);
171
+
172
+ status = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, &len);
173
+ if (status < 0) {
174
+ return status;
175
+ }
176
+
177
+ return size;
178
+ }
179
+
180
+ int
181
+ _nc_atoi(uint8_t *line, size_t n)
182
+ {
183
+ int value;
184
+
185
+ if (n == 0) {
186
+ return -1;
187
+ }
188
+
189
+ for (value = 0; n--; line++) {
190
+ if (*line < '0' || *line > '9') {
191
+ return -1;
192
+ }
193
+
194
+ value = value * 10 + (*line - '0');
195
+ }
196
+
197
+ if (value < 0) {
198
+ return -1;
199
+ }
200
+
201
+ return value;
202
+ }
203
+
204
+ bool
205
+ nc_valid_port(int n)
206
+ {
207
+ if (n < 1 || n > UINT16_MAX) {
208
+ return false;
209
+ }
210
+
211
+ return true;
212
+ }
213
+
214
+ void *
215
+ _nc_alloc(size_t size, const char *name, int line)
216
+ {
217
+ void *p;
218
+
219
+ ASSERT(size != 0);
220
+
221
+ p = malloc(size);
222
+ if (p == NULL) {
223
+ log_error("malloc(%zu) failed @ %s:%d", size, name, line);
224
+ } else {
225
+ log_debug(LOG_VVERB, "malloc(%zu) at %p @ %s:%d", size, p, name, line);
226
+ }
227
+
228
+ return p;
229
+ }
230
+
231
+ void *
232
+ _nc_zalloc(size_t size, const char *name, int line)
233
+ {
234
+ void *p;
235
+
236
+ p = _nc_alloc(size, name, line);
237
+ if (p != NULL) {
238
+ memset(p, 0, size);
239
+ }
240
+
241
+ return p;
242
+ }
243
+
244
+ void *
245
+ _nc_calloc(size_t nmemb, size_t size, const char *name, int line)
246
+ {
247
+ return _nc_zalloc(nmemb * size, name, line);
248
+ }
249
+
250
+ void *
251
+ _nc_realloc(void *ptr, size_t size, const char *name, int line)
252
+ {
253
+ void *p;
254
+
255
+ ASSERT(size != 0);
256
+
257
+ p = realloc(ptr, size);
258
+ if (p == NULL) {
259
+ log_error("realloc(%zu) failed @ %s:%d", size, name, line);
260
+ } else {
261
+ log_debug(LOG_VVERB, "realloc(%zu) at %p @ %s:%d", size, p, name, line);
262
+ }
263
+
264
+ return p;
265
+ }
266
+
267
+ void
268
+ _nc_free(void *ptr, const char *name, int line)
269
+ {
270
+ ASSERT(ptr != NULL);
271
+ log_debug(LOG_VVERB, "free(%p) @ %s:%d", ptr, name, line);
272
+ free(ptr);
273
+ }
274
+
275
+ void
276
+ nc_stacktrace(int skip_count)
277
+ {
278
+ void *stack[64];
279
+ char **symbols;
280
+ int size, i, j;
281
+
282
+ size = backtrace(stack, 64);
283
+ symbols = backtrace_symbols(stack, size);
284
+ if (symbols == NULL) {
285
+ return;
286
+ }
287
+
288
+ skip_count++; /* skip the current frame also */
289
+
290
+ for (i = skip_count, j = 0; i < size; i++, j++) {
291
+ loga("[%d] %s", j, symbols[i]);
292
+ }
293
+
294
+ free(symbols);
295
+ }
296
+
297
+ void
298
+ nc_assert(const char *cond, const char *file, int line, int panic)
299
+ {
300
+ log_error("assert '%s' failed @ (%s, %d)", cond, file, line);
301
+ if (panic) {
302
+ nc_stacktrace(1);
303
+ abort();
304
+ }
305
+ }
306
+
307
+ int
308
+ _vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
309
+ {
310
+ int n;
311
+
312
+ n = vsnprintf(buf, size, fmt, args);
313
+
314
+ /*
315
+ * The return value is the number of characters which would be written
316
+ * into buf not including the trailing '\0'. If size is == 0 the
317
+ * function returns 0.
318
+ *
319
+ * On error, the function also returns 0. This is to allow idiom such
320
+ * as len += _vscnprintf(...)
321
+ *
322
+ * See: http://lwn.net/Articles/69419/
323
+ */
324
+ if (n <= 0) {
325
+ return 0;
326
+ }
327
+
328
+ if (n < (int) size) {
329
+ return n;
330
+ }
331
+
332
+ return (int)(size - 1);
333
+ }
334
+
335
+ int
336
+ _scnprintf(char *buf, size_t size, const char *fmt, ...)
337
+ {
338
+ va_list args;
339
+ int n;
340
+
341
+ va_start(args, fmt);
342
+ n = _vscnprintf(buf, size, fmt, args);
343
+ va_end(args);
344
+
345
+ return n;
346
+ }
347
+
348
+ /*
349
+ * Send n bytes on a blocking descriptor
350
+ */
351
+ ssize_t
352
+ _nc_sendn(int sd, const void *vptr, size_t n)
353
+ {
354
+ size_t nleft;
355
+ ssize_t nsend;
356
+ const char *ptr;
357
+
358
+ ptr = vptr;
359
+ nleft = n;
360
+ while (nleft > 0) {
361
+ nsend = send(sd, ptr, nleft, 0);
362
+ if (nsend < 0) {
363
+ if (errno == EINTR) {
364
+ continue;
365
+ }
366
+ return nsend;
367
+ }
368
+ if (nsend == 0) {
369
+ return -1;
370
+ }
371
+
372
+ nleft -= (size_t)nsend;
373
+ ptr += nsend;
374
+ }
375
+
376
+ return (ssize_t)n;
377
+ }
378
+
379
+ /*
380
+ * Recv n bytes from a blocking descriptor
381
+ */
382
+ ssize_t
383
+ _nc_recvn(int sd, void *vptr, size_t n)
384
+ {
385
+ size_t nleft;
386
+ ssize_t nrecv;
387
+ char *ptr;
388
+
389
+ ptr = vptr;
390
+ nleft = n;
391
+ while (nleft > 0) {
392
+ nrecv = recv(sd, ptr, nleft, 0);
393
+ if (nrecv < 0) {
394
+ if (errno == EINTR) {
395
+ continue;
396
+ }
397
+ return nrecv;
398
+ }
399
+ if (nrecv == 0) {
400
+ break;
401
+ }
402
+
403
+ nleft -= (size_t)nrecv;
404
+ ptr += nrecv;
405
+ }
406
+
407
+ return (ssize_t)(n - nleft);
408
+ }
409
+
410
+ /*
411
+ * Return the current time in microseconds since Epoch
412
+ */
413
+ int64_t
414
+ nc_usec_now(void)
415
+ {
416
+ struct timeval now;
417
+ int64_t usec;
418
+ int status;
419
+
420
+ status = gettimeofday(&now, NULL);
421
+ if (status < 0) {
422
+ log_error("gettimeofday failed: %s", strerror(errno));
423
+ return -1;
424
+ }
425
+
426
+ usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec;
427
+
428
+ return usec;
429
+ }
430
+
431
+ /*
432
+ * Return the current time in milliseconds since Epoch
433
+ */
434
+ int64_t
435
+ nc_msec_now(void)
436
+ {
437
+ return nc_usec_now() / 1000LL;
438
+ }
439
+
440
+ static int
441
+ nc_resolve_inet(struct string *name, int port, struct sockinfo *si)
442
+ {
443
+ int status;
444
+ struct addrinfo *ai, *cai; /* head and current addrinfo */
445
+ struct addrinfo hints;
446
+ char *node, service[NC_UINTMAX_MAXLEN];
447
+ bool found;
448
+
449
+ ASSERT(nc_valid_port(port));
450
+
451
+ memset(&hints, 0, sizeof(hints));
452
+ hints.ai_flags = AI_NUMERICSERV;
453
+ hints.ai_family = AF_UNSPEC; /* AF_INET or AF_INET6 */
454
+ hints.ai_socktype = SOCK_STREAM;
455
+ hints.ai_protocol = 0;
456
+ hints.ai_addrlen = 0;
457
+ hints.ai_addr = NULL;
458
+ hints.ai_canonname = NULL;
459
+
460
+ if (name != NULL) {
461
+ node = (char *)name->data;
462
+ } else {
463
+ /*
464
+ * If AI_PASSIVE flag is specified in hints.ai_flags, and node is
465
+ * NULL, then the returned socket addresses will be suitable for
466
+ * bind(2)ing a socket that will accept(2) connections. The returned
467
+ * socket address will contain the wildcard IP address.
468
+ */
469
+ node = NULL;
470
+ hints.ai_flags |= AI_PASSIVE;
471
+ }
472
+
473
+ nc_snprintf(service, NC_UINTMAX_MAXLEN, "%d", port);
474
+
475
+ status = getaddrinfo(node, service, &hints, &ai);
476
+ if (status < 0) {
477
+ log_error("address resolution of node '%s' service '%s' failed: %s",
478
+ node, service, gai_strerror(status));
479
+ return -1;
480
+ }
481
+
482
+ /*
483
+ * getaddrinfo() can return a linked list of more than one addrinfo,
484
+ * since we requested for both AF_INET and AF_INET6 addresses and the
485
+ * host itself can be multi-homed. Since we don't care whether we are
486
+ * using ipv4 or ipv6, we just use the first address from this collection
487
+ * in the order in which it was returned.
488
+ *
489
+ * The sorting function used within getaddrinfo() is defined in RFC 3484;
490
+ * the order can be tweaked for a particular system by editing
491
+ * /etc/gai.conf
492
+ */
493
+ for (cai = ai, found = false; cai != NULL; cai = cai->ai_next) {
494
+ si->family = cai->ai_family;
495
+ si->addrlen = cai->ai_addrlen;
496
+ nc_memcpy(&si->addr, cai->ai_addr, si->addrlen);
497
+ found = true;
498
+ break;
499
+ }
500
+
501
+ freeaddrinfo(ai);
502
+
503
+ return !found ? -1 : 0;
504
+ }
505
+
506
+ static int
507
+ nc_resolve_unix(struct string *name, struct sockinfo *si)
508
+ {
509
+ struct sockaddr_un *un;
510
+
511
+ if (name->len >= NC_UNIX_ADDRSTRLEN) {
512
+ return -1;
513
+ }
514
+
515
+ un = &si->addr.un;
516
+
517
+ un->sun_family = AF_UNIX;
518
+ nc_memcpy(un->sun_path, name->data, name->len);
519
+ un->sun_path[name->len] = '\0';
520
+
521
+ si->family = AF_UNIX;
522
+ si->addrlen = sizeof(*un);
523
+ /* si->addr is an alias of un */
524
+
525
+ return 0;
526
+ }
527
+
528
+ /*
529
+ * Resolve a hostname and service by translating it to socket address and
530
+ * return it in si
531
+ *
532
+ * This routine is reentrant
533
+ */
534
+ int
535
+ nc_resolve(struct string *name, int port, struct sockinfo *si)
536
+ {
537
+ if (name != NULL && name->data[0] == '/') {
538
+ return nc_resolve_unix(name, si);
539
+ }
540
+
541
+ return nc_resolve_inet(name, port, si);
542
+ }
543
+
544
+ /*
545
+ * Unresolve the socket address by translating it to a character string
546
+ * describing the host and service
547
+ *
548
+ * This routine is not reentrant
549
+ */
550
+ char *
551
+ nc_unresolve_addr(struct sockaddr *addr, socklen_t addrlen)
552
+ {
553
+ static char unresolve[NI_MAXHOST + NI_MAXSERV];
554
+ static char host[NI_MAXHOST], service[NI_MAXSERV];
555
+ int status;
556
+
557
+ status = getnameinfo(addr, addrlen, host, sizeof(host),
558
+ service, sizeof(service),
559
+ NI_NUMERICHOST | NI_NUMERICSERV);
560
+ if (status < 0) {
561
+ return "unknown";
562
+ }
563
+
564
+ nc_snprintf(unresolve, sizeof(unresolve), "%s:%s", host, service);
565
+
566
+ return unresolve;
567
+ }
568
+
569
+ /*
570
+ * Unresolve the socket descriptor peer address by translating it to a
571
+ * character string describing the host and service
572
+ *
573
+ * This routine is not reentrant
574
+ */
575
+ char *
576
+ nc_unresolve_peer_desc(int sd)
577
+ {
578
+ static struct sockinfo si;
579
+ struct sockaddr *addr;
580
+ socklen_t addrlen;
581
+ int status;
582
+
583
+ memset(&si, 0, sizeof(si));
584
+ addr = (struct sockaddr *)&si.addr;
585
+ addrlen = sizeof(si.addr);
586
+
587
+ status = getpeername(sd, addr, &addrlen);
588
+ if (status < 0) {
589
+ return "unknown";
590
+ }
591
+
592
+ return nc_unresolve_addr(addr, addrlen);
593
+ }
594
+
595
+ /*
596
+ * Unresolve the socket descriptor address by translating it to a
597
+ * character string describing the host and service
598
+ *
599
+ * This routine is not reentrant
600
+ */
601
+ char *
602
+ nc_unresolve_desc(int sd)
603
+ {
604
+ static struct sockinfo si;
605
+ struct sockaddr *addr;
606
+ socklen_t addrlen;
607
+ int status;
608
+
609
+ memset(&si, 0, sizeof(si));
610
+ addr = (struct sockaddr *)&si.addr;
611
+ addrlen = sizeof(si.addr);
612
+
613
+ status = getsockname(sd, addr, &addrlen);
614
+ if (status < 0) {
615
+ return "unknown";
616
+ }
617
+
618
+ return nc_unresolve_addr(addr, addrlen);
619
+ }