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,348 @@
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 <nc_core.h>
19
+
20
+ void
21
+ rbtree_node_init(struct rbnode *node)
22
+ {
23
+ node->left = NULL;
24
+ node->right = NULL;
25
+ node->parent = NULL;
26
+ node->key = 0ULL;
27
+ node->data = NULL;
28
+ /* color is left uninitialized */
29
+ }
30
+
31
+ void
32
+ rbtree_init(struct rbtree *tree, struct rbnode *node)
33
+ {
34
+ rbtree_node_init(node);
35
+ rbtree_black(node);
36
+ tree->root = node;
37
+ tree->sentinel = node;
38
+ }
39
+
40
+ static struct rbnode *
41
+ rbtree_node_min(struct rbnode *node, struct rbnode *sentinel)
42
+ {
43
+ /* traverse left links */
44
+
45
+ while (node->left != sentinel) {
46
+ node = node->left;
47
+ }
48
+
49
+ return node;
50
+ }
51
+
52
+ struct rbnode *
53
+ rbtree_min(struct rbtree *tree)
54
+ {
55
+ struct rbnode *node = tree->root;
56
+ struct rbnode *sentinel = tree->sentinel;
57
+
58
+ /* empty tree */
59
+
60
+ if (node == sentinel) {
61
+ return NULL;
62
+ }
63
+
64
+ return rbtree_node_min(node, sentinel);
65
+ }
66
+
67
+ static void
68
+ rbtree_left_rotate(struct rbnode **root, struct rbnode *sentinel,
69
+ struct rbnode *node)
70
+ {
71
+ struct rbnode *temp;
72
+
73
+ temp = node->right;
74
+ node->right = temp->left;
75
+
76
+ if (temp->left != sentinel) {
77
+ temp->left->parent = node;
78
+ }
79
+
80
+ temp->parent = node->parent;
81
+
82
+ if (node == *root) {
83
+ *root = temp;
84
+ } else if (node == node->parent->left) {
85
+ node->parent->left = temp;
86
+ } else {
87
+ node->parent->right = temp;
88
+ }
89
+
90
+ temp->left = node;
91
+ node->parent = temp;
92
+ }
93
+
94
+ static void
95
+ rbtree_right_rotate(struct rbnode **root, struct rbnode *sentinel,
96
+ struct rbnode *node)
97
+ {
98
+ struct rbnode *temp;
99
+
100
+ temp = node->left;
101
+ node->left = temp->right;
102
+
103
+ if (temp->right != sentinel) {
104
+ temp->right->parent = node;
105
+ }
106
+
107
+ temp->parent = node->parent;
108
+
109
+ if (node == *root) {
110
+ *root = temp;
111
+ } else if (node == node->parent->right) {
112
+ node->parent->right = temp;
113
+ } else {
114
+ node->parent->left = temp;
115
+ }
116
+
117
+ temp->right = node;
118
+ node->parent = temp;
119
+ }
120
+
121
+ void
122
+ rbtree_insert(struct rbtree *tree, struct rbnode *node)
123
+ {
124
+ struct rbnode **root = &tree->root;
125
+ struct rbnode *sentinel = tree->sentinel;
126
+ struct rbnode *temp, **p;
127
+
128
+ /* empty tree */
129
+
130
+ if (*root == sentinel) {
131
+ node->parent = NULL;
132
+ node->left = sentinel;
133
+ node->right = sentinel;
134
+ rbtree_black(node);
135
+ *root = node;
136
+ return;
137
+ }
138
+
139
+ /* a binary tree insert */
140
+
141
+ temp = *root;
142
+ for (;;) {
143
+
144
+ p = (node->key < temp->key) ? &temp->left : &temp->right;
145
+ if (*p == sentinel) {
146
+ break;
147
+ }
148
+ temp = *p;
149
+ }
150
+
151
+ *p = node;
152
+ node->parent = temp;
153
+ node->left = sentinel;
154
+ node->right = sentinel;
155
+ rbtree_red(node);
156
+
157
+ /* re-balance tree */
158
+
159
+ while (node != *root && rbtree_is_red(node->parent)) {
160
+
161
+ if (node->parent == node->parent->parent->left) {
162
+ temp = node->parent->parent->right;
163
+
164
+ if (rbtree_is_red(temp)) {
165
+ rbtree_black(node->parent);
166
+ rbtree_black(temp);
167
+ rbtree_red(node->parent->parent);
168
+ node = node->parent->parent;
169
+ } else {
170
+ if (node == node->parent->right) {
171
+ node = node->parent;
172
+ rbtree_left_rotate(root, sentinel, node);
173
+ }
174
+
175
+ rbtree_black(node->parent);
176
+ rbtree_red(node->parent->parent);
177
+ rbtree_right_rotate(root, sentinel, node->parent->parent);
178
+ }
179
+ } else {
180
+ temp = node->parent->parent->left;
181
+
182
+ if (rbtree_is_red(temp)) {
183
+ rbtree_black(node->parent);
184
+ rbtree_black(temp);
185
+ rbtree_red(node->parent->parent);
186
+ node = node->parent->parent;
187
+ } else {
188
+ if (node == node->parent->left) {
189
+ node = node->parent;
190
+ rbtree_right_rotate(root, sentinel, node);
191
+ }
192
+
193
+ rbtree_black(node->parent);
194
+ rbtree_red(node->parent->parent);
195
+ rbtree_left_rotate(root, sentinel, node->parent->parent);
196
+ }
197
+ }
198
+ }
199
+
200
+ rbtree_black(*root);
201
+ }
202
+
203
+ void
204
+ rbtree_delete(struct rbtree *tree, struct rbnode *node)
205
+ {
206
+ struct rbnode **root = &tree->root;
207
+ struct rbnode *sentinel = tree->sentinel;
208
+ struct rbnode *subst, *temp, *w;
209
+ uint8_t red;
210
+
211
+ /* a binary tree delete */
212
+
213
+ if (node->left == sentinel) {
214
+ temp = node->right;
215
+ subst = node;
216
+ } else if (node->right == sentinel) {
217
+ temp = node->left;
218
+ subst = node;
219
+ } else {
220
+ subst = rbtree_node_min(node->right, sentinel);
221
+ if (subst->left != sentinel) {
222
+ temp = subst->left;
223
+ } else {
224
+ temp = subst->right;
225
+ }
226
+ }
227
+
228
+ if (subst == *root) {
229
+ *root = temp;
230
+ rbtree_black(temp);
231
+
232
+ rbtree_node_init(node);
233
+
234
+ return;
235
+ }
236
+
237
+ red = rbtree_is_red(subst);
238
+
239
+ if (subst == subst->parent->left) {
240
+ subst->parent->left = temp;
241
+ } else {
242
+ subst->parent->right = temp;
243
+ }
244
+
245
+ if (subst == node) {
246
+ temp->parent = subst->parent;
247
+ } else {
248
+
249
+ if (subst->parent == node) {
250
+ temp->parent = subst;
251
+ } else {
252
+ temp->parent = subst->parent;
253
+ }
254
+
255
+ subst->left = node->left;
256
+ subst->right = node->right;
257
+ subst->parent = node->parent;
258
+ rbtree_copy_color(subst, node);
259
+
260
+ if (node == *root) {
261
+ *root = subst;
262
+ } else {
263
+ if (node == node->parent->left) {
264
+ node->parent->left = subst;
265
+ } else {
266
+ node->parent->right = subst;
267
+ }
268
+ }
269
+
270
+ if (subst->left != sentinel) {
271
+ subst->left->parent = subst;
272
+ }
273
+
274
+ if (subst->right != sentinel) {
275
+ subst->right->parent = subst;
276
+ }
277
+ }
278
+
279
+ rbtree_node_init(node);
280
+
281
+ if (red) {
282
+ return;
283
+ }
284
+
285
+ /* a delete fixup */
286
+
287
+ while (temp != *root && rbtree_is_black(temp)) {
288
+
289
+ if (temp == temp->parent->left) {
290
+ w = temp->parent->right;
291
+
292
+ if (rbtree_is_red(w)) {
293
+ rbtree_black(w);
294
+ rbtree_red(temp->parent);
295
+ rbtree_left_rotate(root, sentinel, temp->parent);
296
+ w = temp->parent->right;
297
+ }
298
+
299
+ if (rbtree_is_black(w->left) && rbtree_is_black(w->right)) {
300
+ rbtree_red(w);
301
+ temp = temp->parent;
302
+ } else {
303
+ if (rbtree_is_black(w->right)) {
304
+ rbtree_black(w->left);
305
+ rbtree_red(w);
306
+ rbtree_right_rotate(root, sentinel, w);
307
+ w = temp->parent->right;
308
+ }
309
+
310
+ rbtree_copy_color(w, temp->parent);
311
+ rbtree_black(temp->parent);
312
+ rbtree_black(w->right);
313
+ rbtree_left_rotate(root, sentinel, temp->parent);
314
+ temp = *root;
315
+ }
316
+
317
+ } else {
318
+ w = temp->parent->left;
319
+
320
+ if (rbtree_is_red(w)) {
321
+ rbtree_black(w);
322
+ rbtree_red(temp->parent);
323
+ rbtree_right_rotate(root, sentinel, temp->parent);
324
+ w = temp->parent->left;
325
+ }
326
+
327
+ if (rbtree_is_black(w->left) && rbtree_is_black(w->right)) {
328
+ rbtree_red(w);
329
+ temp = temp->parent;
330
+ } else {
331
+ if (rbtree_is_black(w->left)) {
332
+ rbtree_black(w->right);
333
+ rbtree_red(w);
334
+ rbtree_left_rotate(root, sentinel, w);
335
+ w = temp->parent->left;
336
+ }
337
+
338
+ rbtree_copy_color(w, temp->parent);
339
+ rbtree_black(temp->parent);
340
+ rbtree_black(w->left);
341
+ rbtree_right_rotate(root, sentinel, temp->parent);
342
+ temp = *root;
343
+ }
344
+ }
345
+ }
346
+
347
+ rbtree_black(temp);
348
+ }
@@ -0,0 +1,47 @@
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_RBTREE_
19
+ #define _NC_RBTREE_
20
+
21
+ #define rbtree_red(_node) ((_node)->color = 1)
22
+ #define rbtree_black(_node) ((_node)->color = 0)
23
+ #define rbtree_is_red(_node) ((_node)->color)
24
+ #define rbtree_is_black(_node) (!rbtree_is_red(_node))
25
+ #define rbtree_copy_color(_n1, _n2) ((_n1)->color = (_n2)->color)
26
+
27
+ struct rbnode {
28
+ struct rbnode *left; /* left link */
29
+ struct rbnode *right; /* right link */
30
+ struct rbnode *parent; /* parent link */
31
+ int64_t key; /* key for ordering */
32
+ void *data; /* opaque data */
33
+ uint8_t color; /* red | black */
34
+ };
35
+
36
+ struct rbtree {
37
+ struct rbnode *root; /* root node */
38
+ struct rbnode *sentinel; /* nil node */
39
+ };
40
+
41
+ void rbtree_node_init(struct rbnode *node);
42
+ void rbtree_init(struct rbtree *tree, struct rbnode *node);
43
+ struct rbnode *rbtree_min(struct rbtree *tree);
44
+ void rbtree_insert(struct rbtree *tree, struct rbnode *node);
45
+ void rbtree_delete(struct rbtree *tree, struct rbnode *node);
46
+
47
+ #endif
@@ -0,0 +1,588 @@
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 <nc_core.h>
19
+ #include <nc_server.h>
20
+ #include <nc_event.h>
21
+
22
+ struct msg *
23
+ req_get(struct conn *conn)
24
+ {
25
+ struct msg *msg;
26
+
27
+ ASSERT(conn->client && !conn->proxy);
28
+
29
+ msg = msg_get(conn, true, conn->redis);
30
+ if (msg == NULL) {
31
+ conn->err = errno;
32
+ }
33
+
34
+ return msg;
35
+ }
36
+
37
+ void
38
+ req_put(struct msg *msg)
39
+ {
40
+ struct msg *pmsg; /* peer message (response) */
41
+
42
+ ASSERT(msg->request);
43
+
44
+ pmsg = msg->peer;
45
+ if (pmsg != NULL) {
46
+ ASSERT(!pmsg->request && pmsg->peer == msg);
47
+ msg->peer = NULL;
48
+ pmsg->peer = NULL;
49
+ rsp_put(pmsg);
50
+ }
51
+
52
+ msg_tmo_delete(msg);
53
+
54
+ msg_put(msg);
55
+ }
56
+
57
+ /*
58
+ * Return true if request is done, false otherwise
59
+ *
60
+ * A request is done, if we received response for the given request.
61
+ * A request vector is done if we received responses for all its
62
+ * fragments.
63
+ */
64
+ bool
65
+ req_done(struct conn *conn, struct msg *msg)
66
+ {
67
+ struct msg *cmsg, *pmsg; /* current and previous message */
68
+ uint64_t id; /* fragment id */
69
+ uint32_t nfragment; /* # fragment */
70
+
71
+ ASSERT(conn->client && !conn->proxy);
72
+ ASSERT(msg->request);
73
+
74
+ if (!msg->done) {
75
+ return false;
76
+ }
77
+
78
+ id = msg->frag_id;
79
+ if (id == 0) {
80
+ return true;
81
+ }
82
+
83
+ if (msg->fdone) {
84
+ /* request has already been marked as done */
85
+ return true;
86
+ }
87
+
88
+ /* check all fragments of the given request vector are done */
89
+
90
+ for (pmsg = msg, cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe);
91
+ cmsg != NULL && cmsg->frag_id == id;
92
+ pmsg = cmsg, cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) {
93
+
94
+ if (!cmsg->done) {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ for (pmsg = msg, cmsg = TAILQ_NEXT(msg, c_tqe);
100
+ cmsg != NULL && cmsg->frag_id == id;
101
+ pmsg = cmsg, cmsg = TAILQ_NEXT(cmsg, c_tqe)) {
102
+
103
+ if (!cmsg->done) {
104
+ return false;
105
+ }
106
+ }
107
+
108
+ if (!pmsg->last_fragment) {
109
+ return false;
110
+ }
111
+
112
+ /*
113
+ * At this point, all the fragments including the last fragment have
114
+ * been received.
115
+ *
116
+ * Mark all fragments of the given request vector to be done to speed up
117
+ * future req_done calls for any of fragments of this request
118
+ */
119
+
120
+ msg->fdone = 1;
121
+ nfragment = 1;
122
+
123
+ for (pmsg = msg, cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe);
124
+ cmsg != NULL && cmsg->frag_id == id;
125
+ pmsg = cmsg, cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) {
126
+ cmsg->fdone = 1;
127
+ nfragment++;
128
+ }
129
+
130
+ for (pmsg = msg, cmsg = TAILQ_NEXT(msg, c_tqe);
131
+ cmsg != NULL && cmsg->frag_id == id;
132
+ pmsg = cmsg, cmsg = TAILQ_NEXT(cmsg, c_tqe)) {
133
+ cmsg->fdone = 1;
134
+ nfragment++;
135
+ }
136
+
137
+ ASSERT(msg->frag_owner->nfrag == nfragment);
138
+
139
+ msg->post_coalesce(msg->frag_owner);
140
+
141
+ log_debug(LOG_DEBUG, "req from c %d with fid %"PRIu64" and %"PRIu32" "
142
+ "fragments is done", conn->sd, id, nfragment);
143
+
144
+ return true;
145
+ }
146
+
147
+ /*
148
+ * Return true if request is in error, false otherwise
149
+ *
150
+ * A request is in error, if there was an error in receiving response for the
151
+ * given request. A multiget request is in error if there was an error in
152
+ * receiving response for any its fragments.
153
+ */
154
+ bool
155
+ req_error(struct conn *conn, struct msg *msg)
156
+ {
157
+ struct msg *cmsg; /* current message */
158
+ uint64_t id;
159
+ uint32_t nfragment;
160
+
161
+ ASSERT(msg->request && req_done(conn, msg));
162
+
163
+ if (msg->error) {
164
+ return true;
165
+ }
166
+
167
+ id = msg->frag_id;
168
+ if (id == 0) {
169
+ return false;
170
+ }
171
+
172
+ if (msg->ferror) {
173
+ /* request has already been marked to be in error */
174
+ return true;
175
+ }
176
+
177
+ /* check if any of the fragments of the given request are in error */
178
+
179
+ for (cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe);
180
+ cmsg != NULL && cmsg->frag_id == id;
181
+ cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) {
182
+
183
+ if (cmsg->error) {
184
+ goto ferror;
185
+ }
186
+ }
187
+
188
+ for (cmsg = TAILQ_NEXT(msg, c_tqe);
189
+ cmsg != NULL && cmsg->frag_id == id;
190
+ cmsg = TAILQ_NEXT(cmsg, c_tqe)) {
191
+
192
+ if (cmsg->error) {
193
+ goto ferror;
194
+ }
195
+ }
196
+
197
+ return false;
198
+
199
+ ferror:
200
+
201
+ /*
202
+ * Mark all fragments of the given request to be in error to speed up
203
+ * future req_error calls for any of fragments of this request
204
+ */
205
+
206
+ msg->ferror = 1;
207
+ nfragment = 1;
208
+
209
+ for (cmsg = TAILQ_PREV(msg, msg_tqh, c_tqe);
210
+ cmsg != NULL && cmsg->frag_id == id;
211
+ cmsg = TAILQ_PREV(cmsg, msg_tqh, c_tqe)) {
212
+ cmsg->ferror = 1;
213
+ nfragment++;
214
+ }
215
+
216
+ for (cmsg = TAILQ_NEXT(msg, c_tqe);
217
+ cmsg != NULL && cmsg->frag_id == id;
218
+ cmsg = TAILQ_NEXT(cmsg, c_tqe)) {
219
+ cmsg->ferror = 1;
220
+ nfragment++;
221
+ }
222
+
223
+ log_debug(LOG_DEBUG, "req from c %d with fid %"PRIu64" and %"PRIu32" "
224
+ "fragments is in error", conn->sd, id, nfragment);
225
+
226
+ return true;
227
+ }
228
+
229
+ void
230
+ req_server_enqueue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg)
231
+ {
232
+ ASSERT(msg->request);
233
+ ASSERT(!conn->client && !conn->proxy);
234
+
235
+ /*
236
+ * timeout clock starts ticking the instant the message is enqueued into
237
+ * the server in_q; the clock continues to tick until it either expires
238
+ * or the message is dequeued from the server out_q
239
+ *
240
+ * noreply request are free from timeouts because client is not intrested
241
+ * in the reponse anyway!
242
+ */
243
+ if (!msg->noreply) {
244
+ msg_tmo_insert(msg, conn);
245
+ }
246
+
247
+ TAILQ_INSERT_TAIL(&conn->imsg_q, msg, s_tqe);
248
+
249
+ stats_server_incr(ctx, conn->owner, in_queue);
250
+ stats_server_incr_by(ctx, conn->owner, in_queue_bytes, msg->mlen);
251
+ }
252
+
253
+ void
254
+ req_server_dequeue_imsgq(struct context *ctx, struct conn *conn, struct msg *msg)
255
+ {
256
+ ASSERT(msg->request);
257
+ ASSERT(!conn->client && !conn->proxy);
258
+
259
+ TAILQ_REMOVE(&conn->imsg_q, msg, s_tqe);
260
+
261
+ stats_server_decr(ctx, conn->owner, in_queue);
262
+ stats_server_decr_by(ctx, conn->owner, in_queue_bytes, msg->mlen);
263
+ }
264
+
265
+ void
266
+ req_client_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg)
267
+ {
268
+ ASSERT(msg->request);
269
+ ASSERT(conn->client && !conn->proxy);
270
+
271
+ TAILQ_INSERT_TAIL(&conn->omsg_q, msg, c_tqe);
272
+ }
273
+
274
+ void
275
+ req_server_enqueue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg)
276
+ {
277
+ ASSERT(msg->request);
278
+ ASSERT(!conn->client && !conn->proxy);
279
+
280
+ TAILQ_INSERT_TAIL(&conn->omsg_q, msg, s_tqe);
281
+
282
+ stats_server_incr(ctx, conn->owner, out_queue);
283
+ stats_server_incr_by(ctx, conn->owner, out_queue_bytes, msg->mlen);
284
+ }
285
+
286
+ void
287
+ req_client_dequeue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg)
288
+ {
289
+ ASSERT(msg->request);
290
+ ASSERT(conn->client && !conn->proxy);
291
+
292
+ TAILQ_REMOVE(&conn->omsg_q, msg, c_tqe);
293
+ }
294
+
295
+ void
296
+ req_server_dequeue_omsgq(struct context *ctx, struct conn *conn, struct msg *msg)
297
+ {
298
+ ASSERT(msg->request);
299
+ ASSERT(!conn->client && !conn->proxy);
300
+
301
+ msg_tmo_delete(msg);
302
+
303
+ TAILQ_REMOVE(&conn->omsg_q, msg, s_tqe);
304
+
305
+ stats_server_decr(ctx, conn->owner, out_queue);
306
+ stats_server_decr_by(ctx, conn->owner, out_queue_bytes, msg->mlen);
307
+ }
308
+
309
+ struct msg *
310
+ req_recv_next(struct context *ctx, struct conn *conn, bool alloc)
311
+ {
312
+ struct msg *msg;
313
+
314
+ ASSERT(conn->client && !conn->proxy);
315
+
316
+ if (conn->eof) {
317
+ msg = conn->rmsg;
318
+
319
+ /* client sent eof before sending the entire request */
320
+ if (msg != NULL) {
321
+ conn->rmsg = NULL;
322
+
323
+ ASSERT(msg->peer == NULL);
324
+ ASSERT(msg->request && !msg->done);
325
+
326
+ log_error("eof c %d discarding incomplete req %"PRIu64" len "
327
+ "%"PRIu32"", conn->sd, msg->id, msg->mlen);
328
+
329
+ req_put(msg);
330
+ }
331
+
332
+ /*
333
+ * TCP half-close enables the client to terminate its half of the
334
+ * connection (i.e. the client no longer sends data), but it still
335
+ * is able to receive data from the proxy. The proxy closes its
336
+ * half (by sending the second FIN) when the client has no
337
+ * outstanding requests
338
+ */
339
+ if (!conn->active(conn)) {
340
+ conn->done = 1;
341
+ log_debug(LOG_INFO, "c %d is done", conn->sd);
342
+ }
343
+ return NULL;
344
+ }
345
+
346
+ msg = conn->rmsg;
347
+ if (msg != NULL) {
348
+ ASSERT(msg->request);
349
+ return msg;
350
+ }
351
+
352
+ if (!alloc) {
353
+ return NULL;
354
+ }
355
+
356
+ msg = req_get(conn);
357
+ if (msg != NULL) {
358
+ conn->rmsg = msg;
359
+ }
360
+
361
+ return msg;
362
+ }
363
+
364
+ static bool
365
+ req_filter(struct context *ctx, struct conn *conn, struct msg *msg)
366
+ {
367
+ ASSERT(conn->client && !conn->proxy);
368
+
369
+ if (msg_empty(msg)) {
370
+ ASSERT(conn->rmsg == NULL);
371
+ log_debug(LOG_VERB, "filter empty req %"PRIu64" from c %d", msg->id,
372
+ conn->sd);
373
+ req_put(msg);
374
+ return true;
375
+ }
376
+
377
+ /*
378
+ * Handle "quit\r\n", which is the protocol way of doing a
379
+ * passive close
380
+ */
381
+ if (msg->quit) {
382
+ ASSERT(conn->rmsg == NULL);
383
+ log_debug(LOG_INFO, "filter quit req %"PRIu64" from c %d", msg->id,
384
+ conn->sd);
385
+ conn->eof = 1;
386
+ conn->recv_ready = 0;
387
+ req_put(msg);
388
+ return true;
389
+ }
390
+
391
+ return false;
392
+ }
393
+
394
+ static void
395
+ req_forward_error(struct context *ctx, struct conn *conn, struct msg *msg)
396
+ {
397
+ rstatus_t status;
398
+
399
+ ASSERT(conn->client && !conn->proxy);
400
+
401
+ log_debug(LOG_INFO, "forward req %"PRIu64" len %"PRIu32" type %d from "
402
+ "c %d failed: %s", msg->id, msg->mlen, msg->type, conn->sd,
403
+ strerror(errno));
404
+
405
+ msg->done = 1;
406
+ msg->error = 1;
407
+ msg->err = errno;
408
+
409
+ /* noreply request don't expect any response */
410
+ if (msg->noreply) {
411
+ req_put(msg);
412
+ return;
413
+ }
414
+
415
+ if (req_done(conn, TAILQ_FIRST(&conn->omsg_q))) {
416
+ status = event_add_out(ctx->ep, conn);
417
+ if (status != NC_OK) {
418
+ conn->err = errno;
419
+ }
420
+ }
421
+ }
422
+
423
+ static void
424
+ req_forward_stats(struct context *ctx, struct server *server, struct msg *msg)
425
+ {
426
+ ASSERT(msg->request);
427
+
428
+ stats_server_incr(ctx, server, requests);
429
+ stats_server_incr_by(ctx, server, request_bytes, msg->mlen);
430
+ }
431
+
432
+ static void
433
+ req_forward(struct context *ctx, struct conn *c_conn, struct msg *msg)
434
+ {
435
+ rstatus_t status;
436
+ struct conn *s_conn;
437
+ struct server_pool *pool;
438
+ uint8_t *key;
439
+ uint32_t keylen;
440
+
441
+ ASSERT(c_conn->client && !c_conn->proxy);
442
+
443
+ /* enqueue message (request) into client outq, if response is expected */
444
+ if (!msg->noreply) {
445
+ c_conn->enqueue_outq(ctx, c_conn, msg);
446
+ }
447
+
448
+ pool = c_conn->owner;
449
+ key = NULL;
450
+ keylen = 0;
451
+
452
+ /*
453
+ * If hash_tag: is configured for this server pool, we use the part of
454
+ * the key within the hash tag as an input to the distributor. Otherwise
455
+ * we use the full key
456
+ */
457
+ if (!string_empty(&pool->hash_tag)) {
458
+ struct string *tag = &pool->hash_tag;
459
+ uint8_t *tag_start, *tag_end;
460
+
461
+ tag_start = nc_strchr(msg->key_start, msg->key_end, tag->data[0]);
462
+ if (tag_start != NULL) {
463
+ tag_end = nc_strchr(tag_start + 1, msg->key_end, tag->data[1]);
464
+ if (tag_end != NULL) {
465
+ key = tag_start + 1;
466
+ keylen = (uint32_t)(tag_end - key);
467
+ }
468
+ }
469
+ }
470
+
471
+ if (keylen == 0) {
472
+ key = msg->key_start;
473
+ keylen = (uint32_t)(msg->key_end - msg->key_start);
474
+ }
475
+
476
+ s_conn = server_pool_conn(ctx, c_conn->owner, key, keylen);
477
+ if (s_conn == NULL) {
478
+ req_forward_error(ctx, c_conn, msg);
479
+ return;
480
+ }
481
+ ASSERT(!s_conn->client && !s_conn->proxy);
482
+
483
+ /* enqueue the message (request) into server inq */
484
+ if (TAILQ_EMPTY(&s_conn->imsg_q)) {
485
+ status = event_add_out(ctx->ep, s_conn);
486
+ if (status != NC_OK) {
487
+ req_forward_error(ctx, c_conn, msg);
488
+ s_conn->err = errno;
489
+ return;
490
+ }
491
+ }
492
+ s_conn->enqueue_inq(ctx, s_conn, msg);
493
+
494
+ req_forward_stats(ctx, s_conn->owner, msg);
495
+
496
+ log_debug(LOG_VERB, "forward from c %d to s %d req %"PRIu64" len %"PRIu32
497
+ " type %d with key '%.*s'", c_conn->sd, s_conn->sd, msg->id,
498
+ msg->mlen, msg->type, keylen, key);
499
+ }
500
+
501
+ void
502
+ req_recv_done(struct context *ctx, struct conn *conn, struct msg *msg,
503
+ struct msg *nmsg)
504
+ {
505
+ ASSERT(conn->client && !conn->proxy);
506
+ ASSERT(msg->request);
507
+ ASSERT(msg->owner == conn);
508
+ ASSERT(conn->rmsg == msg);
509
+ ASSERT(nmsg == NULL || nmsg->request);
510
+
511
+ /* enqueue next message (request), if any */
512
+ conn->rmsg = nmsg;
513
+
514
+ if (req_filter(ctx, conn, msg)) {
515
+ return;
516
+ }
517
+
518
+ req_forward(ctx, conn, msg);
519
+ }
520
+
521
+ struct msg *
522
+ req_send_next(struct context *ctx, struct conn *conn)
523
+ {
524
+ rstatus_t status;
525
+ struct msg *msg, *nmsg; /* current and next message */
526
+
527
+ ASSERT(!conn->client && !conn->proxy);
528
+
529
+ if (conn->connecting) {
530
+ server_connected(ctx, conn);
531
+ }
532
+
533
+ nmsg = TAILQ_FIRST(&conn->imsg_q);
534
+ if (nmsg == NULL) {
535
+ /* nothing to send as the server inq is empty */
536
+ status = event_del_out(ctx->ep, conn);
537
+ if (status != NC_OK) {
538
+ conn->err = errno;
539
+ }
540
+
541
+ return NULL;
542
+ }
543
+
544
+ msg = conn->smsg;
545
+ if (msg != NULL) {
546
+ ASSERT(msg->request && !msg->done);
547
+ nmsg = TAILQ_NEXT(msg, s_tqe);
548
+ }
549
+
550
+ conn->smsg = nmsg;
551
+
552
+ if (nmsg == NULL) {
553
+ return NULL;
554
+ }
555
+
556
+ ASSERT(nmsg->request && !nmsg->done);
557
+
558
+ log_debug(LOG_VVERB, "send next req %"PRIu64" len %"PRIu32" type %d on "
559
+ "s %d", nmsg->id, nmsg->mlen, nmsg->type, conn->sd);
560
+
561
+ return nmsg;
562
+ }
563
+
564
+ void
565
+ req_send_done(struct context *ctx, struct conn *conn, struct msg *msg)
566
+ {
567
+ ASSERT(!conn->client && !conn->proxy);
568
+ ASSERT(msg != NULL && conn->smsg == NULL);
569
+ ASSERT(msg->request && !msg->done);
570
+ ASSERT(msg->owner != conn);
571
+
572
+ log_debug(LOG_VVERB, "send done req %"PRIu64" len %"PRIu32" type %d on "
573
+ "s %d", msg->id, msg->mlen, msg->type, conn->sd);
574
+
575
+ /* dequeue the message (request) from server inq */
576
+ conn->dequeue_inq(ctx, conn, msg);
577
+
578
+ /*
579
+ * noreply request instructs the server not to send any response. So,
580
+ * enqueue message (request) in server outq, if response is expected.
581
+ * Otherwise, free the noreply request
582
+ */
583
+ if (!msg->noreply) {
584
+ conn->enqueue_outq(ctx, conn, msg);
585
+ } else {
586
+ req_put(msg);
587
+ }
588
+ }