nutcracker 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. data/README.md +22 -0
  2. data/Rakefile +55 -0
  3. data/bin/nutcracker +2 -0
  4. data/ext/nutcracker/ChangeLog +66 -0
  5. data/ext/nutcracker/LICENSE +177 -0
  6. data/ext/nutcracker/Makefile.am +7 -0
  7. data/ext/nutcracker/Makefile.in +726 -0
  8. data/ext/nutcracker/NOTICE +124 -0
  9. data/ext/nutcracker/README.md +240 -0
  10. data/ext/nutcracker/aclocal.m4 +956 -0
  11. data/ext/nutcracker/conf/nutcracker.leaf.yml +10 -0
  12. data/ext/nutcracker/conf/nutcracker.root.yml +8 -0
  13. data/ext/nutcracker/conf/nutcracker.yml +67 -0
  14. data/ext/nutcracker/config.h.in +316 -0
  15. data/ext/nutcracker/config/config.guess +1561 -0
  16. data/ext/nutcracker/config/config.sub +1686 -0
  17. data/ext/nutcracker/config/depcomp +630 -0
  18. data/ext/nutcracker/config/install-sh +520 -0
  19. data/ext/nutcracker/config/ltmain.sh +8413 -0
  20. data/ext/nutcracker/config/missing +376 -0
  21. data/ext/nutcracker/configure +18862 -0
  22. data/ext/nutcracker/configure.ac +155 -0
  23. data/ext/nutcracker/contrib/Makefile.am +3 -0
  24. data/ext/nutcracker/contrib/Makefile.in +560 -0
  25. data/ext/nutcracker/contrib/yaml-0.1.4.tar.gz +0 -0
  26. data/ext/nutcracker/contrib/yaml-0.1.4/LICENSE +19 -0
  27. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.am +20 -0
  28. data/ext/nutcracker/contrib/yaml-0.1.4/Makefile.in +736 -0
  29. data/ext/nutcracker/contrib/yaml-0.1.4/README +27 -0
  30. data/ext/nutcracker/contrib/yaml-0.1.4/aclocal.m4 +956 -0
  31. data/ext/nutcracker/contrib/yaml-0.1.4/config.h.in +80 -0
  32. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.guess +1561 -0
  33. data/ext/nutcracker/contrib/yaml-0.1.4/config/config.sub +1686 -0
  34. data/ext/nutcracker/contrib/yaml-0.1.4/config/depcomp +630 -0
  35. data/ext/nutcracker/contrib/yaml-0.1.4/config/install-sh +520 -0
  36. data/ext/nutcracker/contrib/yaml-0.1.4/config/ltmain.sh +8406 -0
  37. data/ext/nutcracker/contrib/yaml-0.1.4/config/missing +376 -0
  38. data/ext/nutcracker/contrib/yaml-0.1.4/configure +13085 -0
  39. data/ext/nutcracker/contrib/yaml-0.1.4/configure.ac +75 -0
  40. data/ext/nutcracker/contrib/yaml-0.1.4/doc/doxygen.cfg +222 -0
  41. data/ext/nutcracker/contrib/yaml-0.1.4/include/yaml.h +1971 -0
  42. data/ext/nutcracker/contrib/yaml-0.1.4/m4/libtool.m4 +7357 -0
  43. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltoptions.m4 +368 -0
  44. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltsugar.m4 +123 -0
  45. data/ext/nutcracker/contrib/yaml-0.1.4/m4/ltversion.m4 +23 -0
  46. data/ext/nutcracker/contrib/yaml-0.1.4/m4/lt~obsolete.m4 +92 -0
  47. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.am +4 -0
  48. data/ext/nutcracker/contrib/yaml-0.1.4/src/Makefile.in +484 -0
  49. data/ext/nutcracker/contrib/yaml-0.1.4/src/api.c +1392 -0
  50. data/ext/nutcracker/contrib/yaml-0.1.4/src/dumper.c +394 -0
  51. data/ext/nutcracker/contrib/yaml-0.1.4/src/emitter.c +2329 -0
  52. data/ext/nutcracker/contrib/yaml-0.1.4/src/loader.c +432 -0
  53. data/ext/nutcracker/contrib/yaml-0.1.4/src/parser.c +1374 -0
  54. data/ext/nutcracker/contrib/yaml-0.1.4/src/reader.c +465 -0
  55. data/ext/nutcracker/contrib/yaml-0.1.4/src/scanner.c +3570 -0
  56. data/ext/nutcracker/contrib/yaml-0.1.4/src/writer.c +141 -0
  57. data/ext/nutcracker/contrib/yaml-0.1.4/src/yaml_private.h +640 -0
  58. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.am +8 -0
  59. data/ext/nutcracker/contrib/yaml-0.1.4/tests/Makefile.in +675 -0
  60. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor-alt.c +800 -0
  61. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-deconstructor.c +1130 -0
  62. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter-alt.c +217 -0
  63. data/ext/nutcracker/contrib/yaml-0.1.4/tests/example-reformatter.c +202 -0
  64. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-dumper.c +311 -0
  65. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-emitter.c +327 -0
  66. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-loader.c +63 -0
  67. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-parser.c +63 -0
  68. data/ext/nutcracker/contrib/yaml-0.1.4/tests/run-scanner.c +63 -0
  69. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-reader.c +354 -0
  70. data/ext/nutcracker/contrib/yaml-0.1.4/tests/test-version.c +29 -0
  71. data/ext/nutcracker/extconf.rb +5 -0
  72. data/ext/nutcracker/m4/libtool.m4 +7376 -0
  73. data/ext/nutcracker/m4/ltoptions.m4 +368 -0
  74. data/ext/nutcracker/m4/ltsugar.m4 +123 -0
  75. data/ext/nutcracker/m4/ltversion.m4 +23 -0
  76. data/ext/nutcracker/m4/lt~obsolete.m4 +92 -0
  77. data/ext/nutcracker/notes/c-styleguide.txt +425 -0
  78. data/ext/nutcracker/notes/debug.txt +96 -0
  79. data/ext/nutcracker/notes/memcache.txt +123 -0
  80. data/ext/nutcracker/notes/recommendation.md +118 -0
  81. data/ext/nutcracker/notes/redis.md +415 -0
  82. data/ext/nutcracker/notes/socket.txt +131 -0
  83. data/ext/nutcracker/scripts/multi_get.sh +26 -0
  84. data/ext/nutcracker/scripts/nutcracker.init +73 -0
  85. data/ext/nutcracker/scripts/nutcracker.spec +52 -0
  86. data/ext/nutcracker/scripts/pipelined_read.sh +23 -0
  87. data/ext/nutcracker/scripts/pipelined_write.sh +29 -0
  88. data/ext/nutcracker/scripts/populate_memcached.sh +24 -0
  89. data/ext/nutcracker/scripts/redis-check.py +23 -0
  90. data/ext/nutcracker/scripts/redis-check.sh +564 -0
  91. data/ext/nutcracker/src/Makefile.am +46 -0
  92. data/ext/nutcracker/src/Makefile.in +726 -0
  93. data/ext/nutcracker/src/hashkit/Makefile.am +22 -0
  94. data/ext/nutcracker/src/hashkit/Makefile.in +501 -0
  95. data/ext/nutcracker/src/hashkit/nc_crc32.c +105 -0
  96. data/ext/nutcracker/src/hashkit/nc_fnv.c +82 -0
  97. data/ext/nutcracker/src/hashkit/nc_hashkit.h +74 -0
  98. data/ext/nutcracker/src/hashkit/nc_hsieh.c +93 -0
  99. data/ext/nutcracker/src/hashkit/nc_jenkins.c +230 -0
  100. data/ext/nutcracker/src/hashkit/nc_ketama.c +240 -0
  101. data/ext/nutcracker/src/hashkit/nc_md5.c +379 -0
  102. data/ext/nutcracker/src/hashkit/nc_modula.c +144 -0
  103. data/ext/nutcracker/src/hashkit/nc_murmur.c +99 -0
  104. data/ext/nutcracker/src/hashkit/nc_one_at_a_time.c +51 -0
  105. data/ext/nutcracker/src/hashkit/nc_random.c +146 -0
  106. data/ext/nutcracker/src/nc.c +573 -0
  107. data/ext/nutcracker/src/nc_array.c +204 -0
  108. data/ext/nutcracker/src/nc_array.h +73 -0
  109. data/ext/nutcracker/src/nc_client.c +189 -0
  110. data/ext/nutcracker/src/nc_client.h +28 -0
  111. data/ext/nutcracker/src/nc_conf.c +1766 -0
  112. data/ext/nutcracker/src/nc_conf.h +134 -0
  113. data/ext/nutcracker/src/nc_connection.c +392 -0
  114. data/ext/nutcracker/src/nc_connection.h +99 -0
  115. data/ext/nutcracker/src/nc_core.c +334 -0
  116. data/ext/nutcracker/src/nc_core.h +131 -0
  117. data/ext/nutcracker/src/nc_event.c +214 -0
  118. data/ext/nutcracker/src/nc_event.h +39 -0
  119. data/ext/nutcracker/src/nc_log.c +254 -0
  120. data/ext/nutcracker/src/nc_log.h +120 -0
  121. data/ext/nutcracker/src/nc_mbuf.c +285 -0
  122. data/ext/nutcracker/src/nc_mbuf.h +67 -0
  123. data/ext/nutcracker/src/nc_message.c +828 -0
  124. data/ext/nutcracker/src/nc_message.h +253 -0
  125. data/ext/nutcracker/src/nc_proxy.c +359 -0
  126. data/ext/nutcracker/src/nc_proxy.h +34 -0
  127. data/ext/nutcracker/src/nc_queue.h +788 -0
  128. data/ext/nutcracker/src/nc_rbtree.c +348 -0
  129. data/ext/nutcracker/src/nc_rbtree.h +47 -0
  130. data/ext/nutcracker/src/nc_request.c +588 -0
  131. data/ext/nutcracker/src/nc_response.c +332 -0
  132. data/ext/nutcracker/src/nc_server.c +841 -0
  133. data/ext/nutcracker/src/nc_server.h +143 -0
  134. data/ext/nutcracker/src/nc_signal.c +131 -0
  135. data/ext/nutcracker/src/nc_signal.h +34 -0
  136. data/ext/nutcracker/src/nc_stats.c +1188 -0
  137. data/ext/nutcracker/src/nc_stats.h +206 -0
  138. data/ext/nutcracker/src/nc_string.c +109 -0
  139. data/ext/nutcracker/src/nc_string.h +112 -0
  140. data/ext/nutcracker/src/nc_util.c +619 -0
  141. data/ext/nutcracker/src/nc_util.h +214 -0
  142. data/ext/nutcracker/src/proto/Makefile.am +14 -0
  143. data/ext/nutcracker/src/proto/Makefile.in +482 -0
  144. data/ext/nutcracker/src/proto/nc_memcache.c +1306 -0
  145. data/ext/nutcracker/src/proto/nc_proto.h +155 -0
  146. data/ext/nutcracker/src/proto/nc_redis.c +2102 -0
  147. data/lib/nutcracker.rb +7 -0
  148. data/lib/nutcracker/version.rb +3 -0
  149. metadata +194 -0
@@ -0,0 +1,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
+ }