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