nutcracker 0.2.4.1 → 0.2.4.2
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 +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
|