nutcracker 0.2.4.1 → 0.2.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +28 -10
- data/Rakefile +5 -19
- data/bin/nutcracker +6 -1
- data/ext/nutcracker/ChangeLog +9 -0
- data/ext/nutcracker/Makefile.in +54 -29
- data/ext/nutcracker/README.md +13 -11
- data/ext/nutcracker/aclocal.m4 +46 -26
- data/ext/nutcracker/config/config.guess +209 -240
- data/ext/nutcracker/config/config.sub +157 -70
- data/ext/nutcracker/config/depcomp +66 -8
- data/ext/nutcracker/config/install-sh +18 -11
- data/ext/nutcracker/config/ltmain.sh +2632 -1384
- data/ext/nutcracker/config/missing +4 -49
- data/ext/nutcracker/configure +2866 -2118
- data/ext/nutcracker/configure.ac +1 -1
- data/ext/nutcracker/contrib/Makefile.in +17 -10
- data/ext/nutcracker/m4/libtool.m4 +1437 -812
- data/ext/nutcracker/m4/ltoptions.m4 +24 -8
- data/ext/nutcracker/m4/ltversion.m4 +6 -6
- data/ext/nutcracker/m4/lt~obsolete.m4 +9 -3
- data/ext/nutcracker/notes/recommendation.md +21 -2
- data/ext/nutcracker/notes/redis.md +9 -9
- data/ext/nutcracker/scripts/redis-check.sh +9 -0
- data/ext/nutcracker/src/Makefile.in +18 -11
- data/ext/nutcracker/src/hashkit/Makefile.am +1 -0
- data/ext/nutcracker/src/hashkit/Makefile.in +23 -13
- data/ext/nutcracker/src/hashkit/nc_crc16.c +66 -0
- data/ext/nutcracker/src/hashkit/nc_hashkit.h +2 -0
- data/ext/nutcracker/src/hashkit/nc_modula.c +18 -6
- data/ext/nutcracker/src/nc_conf.c +14 -35
- data/ext/nutcracker/src/nc_conf.h +1 -1
- data/ext/nutcracker/src/nc_message.h +2 -0
- data/ext/nutcracker/src/nc_server.c +9 -7
- data/ext/nutcracker/src/proto/Makefile.in +16 -9
- data/ext/nutcracker/src/proto/nc_redis.c +17 -4
- data/lib/nutcracker/version.rb +1 -1
- data/lib/nutcracker.rb +60 -2
- metadata +3 -2
@@ -1109,14 +1109,6 @@ conf_pre_validate(struct conf *cf)
|
|
1109
1109
|
return NC_OK;
|
1110
1110
|
}
|
1111
1111
|
|
1112
|
-
static int
|
1113
|
-
conf_server_pname_cmp(const void *t1, const void *t2)
|
1114
|
-
{
|
1115
|
-
const struct conf_server *s1 = t1, *s2 = t2;
|
1116
|
-
|
1117
|
-
return string_compare(&s1->pname, &s2->pname);
|
1118
|
-
}
|
1119
|
-
|
1120
1112
|
static int
|
1121
1113
|
conf_server_name_cmp(const void *t1, const void *t2)
|
1122
1114
|
{
|
@@ -1156,27 +1148,10 @@ conf_validate_server(struct conf *cf, struct conf_pool *cp)
|
|
1156
1148
|
|
1157
1149
|
/*
|
1158
1150
|
* Disallow duplicate servers - servers with identical "host:port:weight"
|
1159
|
-
* or "name" combination are considered as duplicates
|
1151
|
+
* or "name" combination are considered as duplicates. When server name
|
1152
|
+
* is configured, we only check for duplicate "name" and not for duplicate
|
1153
|
+
* "host:port:weight"
|
1160
1154
|
*/
|
1161
|
-
array_sort(&cp->server, conf_server_pname_cmp);
|
1162
|
-
for (valid = true, i = 0; i < nserver - 1; i++) {
|
1163
|
-
struct conf_server *cs1, *cs2;
|
1164
|
-
|
1165
|
-
cs1 = array_get(&cp->server, i);
|
1166
|
-
cs2 = array_get(&cp->server, i + 1);
|
1167
|
-
|
1168
|
-
if (string_compare(&cs1->pname, &cs2->pname) == 0) {
|
1169
|
-
log_error("conf: pool '%.*s' has servers with same name '%.*s'",
|
1170
|
-
cp->name.len, cp->name.data, cs1->pname.len,
|
1171
|
-
cs1->pname.data);
|
1172
|
-
valid = false;
|
1173
|
-
break;
|
1174
|
-
}
|
1175
|
-
}
|
1176
|
-
if (!valid) {
|
1177
|
-
return NC_ERROR;
|
1178
|
-
}
|
1179
|
-
|
1180
1155
|
array_sort(&cp->server, conf_server_name_cmp);
|
1181
1156
|
for (valid = true, i = 0; i < nserver - 1; i++) {
|
1182
1157
|
struct conf_server *cs1, *cs2;
|
@@ -1497,7 +1472,7 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
|
|
1497
1472
|
struct conf_server *field;
|
1498
1473
|
uint8_t *p, *q, *start;
|
1499
1474
|
uint8_t *pname, *addr, *port, *weight, *name;
|
1500
|
-
uint32_t k, pnamelen, addrlen, portlen, weightlen, namelen;
|
1475
|
+
uint32_t k, delimlen, pnamelen, addrlen, portlen, weightlen, namelen;
|
1501
1476
|
struct string address;
|
1502
1477
|
char delim[] = " ::";
|
1503
1478
|
|
@@ -1514,7 +1489,7 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
|
|
1514
1489
|
|
1515
1490
|
value = array_top(&cf->arg);
|
1516
1491
|
|
1517
|
-
/* parse "hostname:port:weight [name]" from the end */
|
1492
|
+
/* parse "hostname:port:weight [name]" or "/path/unix_socket:weight [name]" from the end */
|
1518
1493
|
p = value->data + value->len - 1;
|
1519
1494
|
start = value->data;
|
1520
1495
|
addr = NULL;
|
@@ -1526,6 +1501,8 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
|
|
1526
1501
|
name = NULL;
|
1527
1502
|
namelen = 0;
|
1528
1503
|
|
1504
|
+
delimlen = value->data[0] == '/' ? 2 : 3;
|
1505
|
+
|
1529
1506
|
for (k = 0; k < sizeof(delim); k++) {
|
1530
1507
|
q = nc_strrchr(p, start, delim[k]);
|
1531
1508
|
if (q == NULL) {
|
@@ -1562,8 +1539,8 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
|
|
1562
1539
|
p = q - 1;
|
1563
1540
|
}
|
1564
1541
|
|
1565
|
-
if (k !=
|
1566
|
-
return "has an invalid \"hostname:port:weight [name]\" format string";
|
1542
|
+
if (k != delimlen) {
|
1543
|
+
return "has an invalid \"hostname:port:weight [name]\"or \"/path/unix_socket:weight [name]\" format string";
|
1567
1544
|
}
|
1568
1545
|
|
1569
1546
|
pname = value->data;
|
@@ -1582,9 +1559,11 @@ conf_add_server(struct conf *cf, struct command *cmd, void *conf)
|
|
1582
1559
|
return "has an invalid weight in \"hostname:port:weight [name]\" format string";
|
1583
1560
|
}
|
1584
1561
|
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1562
|
+
if (value->data[0] != '/') {
|
1563
|
+
field->port = nc_atoi(port, portlen);
|
1564
|
+
if (field->port < 0 || !nc_valid_port(field->port)) {
|
1565
|
+
return "has an invalid port in \"hostname:port:weight [name]\" format string";
|
1566
|
+
}
|
1588
1567
|
}
|
1589
1568
|
|
1590
1569
|
if (name == NULL) {
|
@@ -120,7 +120,7 @@ char *conf_set_string(struct conf *cf, struct command *cmd, void *conf);
|
|
120
120
|
char *conf_set_listen(struct conf *cf, struct command *cmd, void *conf);
|
121
121
|
char *conf_add_server(struct conf *cf, struct command *cmd, void *conf);
|
122
122
|
char *conf_set_num(struct conf *cf, struct command *cmd, void *conf);
|
123
|
-
char *
|
123
|
+
char *conf_set_bool(struct conf *cf, struct command *cmd, void *conf);
|
124
124
|
char *conf_set_hash(struct conf *cf, struct command *cmd, void *conf);
|
125
125
|
char *conf_set_distribution(struct conf *cf, struct command *cmd, void *conf);
|
126
126
|
char *conf_set_hashtag(struct conf *cf, struct command *cmd, void *conf);
|
@@ -71,6 +71,7 @@ typedef enum msg_type {
|
|
71
71
|
MSG_REQ_REDIS_BITCOUNT,
|
72
72
|
MSG_REQ_REDIS_DECR,
|
73
73
|
MSG_REQ_REDIS_DECRBY,
|
74
|
+
MSG_REQ_REDIS_DUMP,
|
74
75
|
MSG_REQ_REDIS_GET,
|
75
76
|
MSG_REQ_REDIS_GETBIT,
|
76
77
|
MSG_REQ_REDIS_GETRANGE,
|
@@ -80,6 +81,7 @@ typedef enum msg_type {
|
|
80
81
|
MSG_REQ_REDIS_INCRBYFLOAT,
|
81
82
|
MSG_REQ_REDIS_MGET,
|
82
83
|
MSG_REQ_REDIS_PSETEX,
|
84
|
+
MSG_REQ_REDIS_RESTORE,
|
83
85
|
MSG_REQ_REDIS_SET,
|
84
86
|
MSG_REQ_REDIS_SETBIT,
|
85
87
|
MSG_REQ_REDIS_SETEX,
|
@@ -451,7 +451,7 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
|
|
451
451
|
log_debug(LOG_VVERB, "connect to server '%.*s'", server->pname.len,
|
452
452
|
server->pname.data);
|
453
453
|
|
454
|
-
|
454
|
+
conn->sd = socket(conn->family, SOCK_STREAM, 0);
|
455
455
|
if (conn->sd < 0) {
|
456
456
|
log_error("socket for server '%.*s' failed: %s", server->pname.len,
|
457
457
|
server->pname.data, strerror(errno));
|
@@ -467,11 +467,13 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
|
|
467
467
|
goto error;
|
468
468
|
}
|
469
469
|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
470
|
+
if (server->pname.data[0] != '/') {
|
471
|
+
status = nc_set_tcpnodelay(conn->sd);
|
472
|
+
if (status != NC_OK) {
|
473
|
+
log_warn("set tcpnodelay on s %d for server '%.*s' failed, ignored: %s",
|
474
|
+
conn->sd, server->pname.len, server->pname.data,
|
475
|
+
strerror(errno));
|
476
|
+
}
|
475
477
|
}
|
476
478
|
|
477
479
|
status = event_add_conn(ctx->ep, conn);
|
@@ -484,7 +486,7 @@ server_connect(struct context *ctx, struct server *server, struct conn *conn)
|
|
484
486
|
|
485
487
|
ASSERT(!conn->connecting && !conn->connected);
|
486
488
|
|
487
|
-
|
489
|
+
status = connect(conn->sd, conn->addr, conn->addrlen);
|
488
490
|
if (status != NC_OK) {
|
489
491
|
if (errno == EINPROGRESS) {
|
490
492
|
conn->connecting = 1;
|
@@ -1,9 +1,9 @@
|
|
1
|
-
# Makefile.in generated by automake 1.11 from Makefile.am.
|
1
|
+
# Makefile.in generated by automake 1.11.3 from Makefile.am.
|
2
2
|
# @configure_input@
|
3
3
|
|
4
4
|
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
5
|
-
# 2003, 2004, 2005, 2006, 2007, 2008, 2009
|
6
|
-
# Inc.
|
5
|
+
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
|
6
|
+
# Foundation, Inc.
|
7
7
|
# This Makefile.in is free software; the Free Software Foundation
|
8
8
|
# gives unlimited permission to copy and/or distribute it,
|
9
9
|
# with or without modifications, as long as this notice is preserved.
|
@@ -93,6 +93,7 @@ CXXFLAGS = @CXXFLAGS@
|
|
93
93
|
CYGPATH_W = @CYGPATH_W@
|
94
94
|
DEFS = @DEFS@
|
95
95
|
DEPDIR = @DEPDIR@
|
96
|
+
DLLTOOL = @DLLTOOL@
|
96
97
|
DSYMUTIL = @DSYMUTIL@
|
97
98
|
DUMPBIN = @DUMPBIN@
|
98
99
|
ECHO_C = @ECHO_C@
|
@@ -116,6 +117,7 @@ LIPO = @LIPO@
|
|
116
117
|
LN_S = @LN_S@
|
117
118
|
LTLIBOBJS = @LTLIBOBJS@
|
118
119
|
MAKEINFO = @MAKEINFO@
|
120
|
+
MANIFEST_TOOL = @MANIFEST_TOOL@
|
119
121
|
MKDIR_P = @MKDIR_P@
|
120
122
|
NM = @NM@
|
121
123
|
NMEDIT = @NMEDIT@
|
@@ -141,6 +143,7 @@ abs_builddir = @abs_builddir@
|
|
141
143
|
abs_srcdir = @abs_srcdir@
|
142
144
|
abs_top_builddir = @abs_top_builddir@
|
143
145
|
abs_top_srcdir = @abs_top_srcdir@
|
146
|
+
ac_ct_AR = @ac_ct_AR@
|
144
147
|
ac_ct_CC = @ac_ct_CC@
|
145
148
|
ac_ct_CXX = @ac_ct_CXX@
|
146
149
|
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
@@ -174,7 +177,6 @@ libdir = @libdir@
|
|
174
177
|
libexecdir = @libexecdir@
|
175
178
|
localedir = @localedir@
|
176
179
|
localstatedir = @localstatedir@
|
177
|
-
lt_ECHO = @lt_ECHO@
|
178
180
|
mandir = @mandir@
|
179
181
|
mkdir_p = @mkdir_p@
|
180
182
|
oldincludedir = @oldincludedir@
|
@@ -237,7 +239,7 @@ $(am__aclocal_m4_deps):
|
|
237
239
|
|
238
240
|
clean-noinstLIBRARIES:
|
239
241
|
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
|
240
|
-
libproto.a: $(libproto_a_OBJECTS) $(libproto_a_DEPENDENCIES)
|
242
|
+
libproto.a: $(libproto_a_OBJECTS) $(libproto_a_DEPENDENCIES) $(EXTRA_libproto_a_DEPENDENCIES)
|
241
243
|
-rm -f libproto.a
|
242
244
|
$(libproto_a_AR) libproto.a $(libproto_a_OBJECTS) $(libproto_a_LIBADD)
|
243
245
|
$(RANLIB) libproto.a
|
@@ -374,10 +376,15 @@ install-am: all-am
|
|
374
376
|
|
375
377
|
installcheck: installcheck-am
|
376
378
|
install-strip:
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
379
|
+
if test -z '$(STRIP)'; then \
|
380
|
+
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
381
|
+
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
382
|
+
install; \
|
383
|
+
else \
|
384
|
+
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
385
|
+
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
386
|
+
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
387
|
+
fi
|
381
388
|
mostlyclean-generic:
|
382
389
|
|
383
390
|
clean-generic:
|
@@ -34,6 +34,7 @@ redis_arg0(struct msg *r)
|
|
34
34
|
case MSG_REQ_REDIS_PTTL:
|
35
35
|
case MSG_REQ_REDIS_TTL:
|
36
36
|
case MSG_REQ_REDIS_TYPE:
|
37
|
+
case MSG_REQ_REDIS_DUMP:
|
37
38
|
|
38
39
|
case MSG_REQ_REDIS_DECR:
|
39
40
|
case MSG_REQ_REDIS_GET:
|
@@ -138,6 +139,8 @@ redis_arg2(struct msg *r)
|
|
138
139
|
case MSG_REQ_REDIS_ZINCRBY:
|
139
140
|
case MSG_REQ_REDIS_ZREMRANGEBYRANK:
|
140
141
|
case MSG_REQ_REDIS_ZREMRANGEBYSCORE:
|
142
|
+
|
143
|
+
case MSG_REQ_REDIS_RESTORE:
|
141
144
|
return true;
|
142
145
|
|
143
146
|
default:
|
@@ -458,6 +461,11 @@ redis_parse_req(struct msg *r)
|
|
458
461
|
break;
|
459
462
|
}
|
460
463
|
|
464
|
+
if (str4icmp(m, 'd', 'u', 'm', 'p')) {
|
465
|
+
r->type = MSG_REQ_REDIS_DUMP;
|
466
|
+
break;
|
467
|
+
}
|
468
|
+
|
461
469
|
if (str4icmp(m, 'h', 'd', 'e', 'l')) {
|
462
470
|
r->type = MSG_REQ_REDIS_HDEL;
|
463
471
|
break;
|
@@ -767,6 +775,11 @@ redis_parse_req(struct msg *r)
|
|
767
775
|
break;
|
768
776
|
}
|
769
777
|
|
778
|
+
if (str7icmp(m, 'r', 'e', 's', 't', 'o', 'r', 'e')) {
|
779
|
+
r->type = MSG_REQ_REDIS_RESTORE;
|
780
|
+
break;
|
781
|
+
}
|
782
|
+
|
770
783
|
break;
|
771
784
|
|
772
785
|
case 8:
|
@@ -947,11 +960,11 @@ redis_parse_req(struct msg *r)
|
|
947
960
|
"key", r->id, r->type);
|
948
961
|
goto error;
|
949
962
|
}
|
950
|
-
if (r->rlen
|
963
|
+
if (r->rlen >= mbuf_data_size()) {
|
951
964
|
log_error("parsed bad req %"PRIu64" of type %d with key "
|
952
|
-
"length %d that
|
953
|
-
"length of %d", r->id, r->type,
|
954
|
-
mbuf_data_size());
|
965
|
+
"length %d that greater than or equal to maximum"
|
966
|
+
" redis key length of %d", r->id, r->type,
|
967
|
+
r->rlen, mbuf_data_size());
|
955
968
|
goto error;
|
956
969
|
}
|
957
970
|
if (r->rnarg == 0) {
|
data/lib/nutcracker/version.rb
CHANGED
data/lib/nutcracker.rb
CHANGED
@@ -1,7 +1,65 @@
|
|
1
1
|
require 'nutcracker/version'
|
2
|
+
require 'socket'
|
3
|
+
require 'json'
|
2
4
|
|
3
5
|
module Nutcracker
|
6
|
+
|
7
|
+
def self.start options
|
8
|
+
Nutcracker::Process.new(options).start
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.executable
|
12
|
+
File.expand_path("../../ext/nutcracker/src/nutcracker", __FILE__)
|
13
|
+
end
|
14
|
+
|
4
15
|
def self.version
|
5
|
-
VERSION
|
16
|
+
Nutcracker::VERSION
|
6
17
|
end
|
7
|
-
|
18
|
+
|
19
|
+
class Process
|
20
|
+
attr_reader :pid, :options
|
21
|
+
|
22
|
+
def initialize options
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
raise RuntimeError, "Nutcracker is already running (#{pid})..." if running?
|
28
|
+
@pid = ::Process.spawn("#{Nutcracker.executable} -c #{options.fetch(:config_file).inspect}")
|
29
|
+
Kernel.at_exit { stop if running? }
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def running?
|
34
|
+
!!(pid and ::Process.getpgid pid rescue false)
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
signal :TERM
|
39
|
+
end
|
40
|
+
|
41
|
+
def kill
|
42
|
+
signal :KILL
|
43
|
+
end
|
44
|
+
|
45
|
+
def join
|
46
|
+
verify_running! and ::Process.waitpid2 pid
|
47
|
+
end
|
48
|
+
|
49
|
+
def stats
|
50
|
+
JSON.parse TCPSocket.new('localhost',22222).read rescue {}
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def verify_running!
|
56
|
+
running? or raise RuntimeError, "Nutcracker isn't running..."
|
57
|
+
end
|
58
|
+
|
59
|
+
def signal term
|
60
|
+
verify_running! and ::Process.kill(term, pid)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nutcracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.4.
|
4
|
+
version: 0.2.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Gem/Bundler benefits for Twitter's Nutcraker C app
|
15
15
|
email: eran@kontera.com
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- ext/nutcracker/scripts/redis-check.sh
|
114
114
|
- ext/nutcracker/src/hashkit/Makefile.am
|
115
115
|
- ext/nutcracker/src/hashkit/Makefile.in
|
116
|
+
- ext/nutcracker/src/hashkit/nc_crc16.c
|
116
117
|
- ext/nutcracker/src/hashkit/nc_crc32.c
|
117
118
|
- ext/nutcracker/src/hashkit/nc_fnv.c
|
118
119
|
- ext/nutcracker/src/hashkit/nc_hashkit.h
|