raindrops 0.13.0 → 0.19.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.
- checksums.yaml +7 -0
- data/.document +1 -2
- data/.gitattributes +4 -0
- data/.gitignore +1 -1
- data/.olddoc.yml +13 -0
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -2
- data/LICENSE +3 -3
- data/README +28 -34
- data/TODO +2 -0
- data/archive/.gitignore +3 -0
- data/archive/slrnpull.conf +4 -0
- data/examples/linux-listener-stats.rb +1 -2
- data/examples/watcher_demo.ru +1 -1
- data/examples/yahns.conf.rb +30 -0
- data/examples/zbatery.conf.rb +4 -1
- data/ext/raindrops/extconf.rb +107 -2
- data/ext/raindrops/linux_inet_diag.c +94 -101
- data/ext/raindrops/raindrops.c +28 -7
- data/ext/raindrops/tcp_info.c +245 -0
- data/lib/raindrops.rb +1 -1
- data/lib/raindrops/aggregate.rb +1 -1
- data/lib/raindrops/aggregate/last_data_recv.rb +1 -5
- data/lib/raindrops/aggregate/pmq.rb +23 -17
- data/lib/raindrops/linux.rb +5 -6
- data/lib/raindrops/middleware.rb +4 -6
- data/lib/raindrops/middleware/proxy.rb +2 -2
- data/lib/raindrops/watcher.rb +13 -13
- data/pkg.mk +26 -50
- data/raindrops.gemspec +14 -21
- data/test/ipv6_enabled.rb +4 -4
- data/test/test_aggregate_pmq.rb +1 -1
- data/test/test_inet_diag_socket.rb +1 -1
- data/test/test_last_data_recv_unicorn.rb +1 -1
- data/test/test_linux.rb +10 -2
- data/test/test_linux_all_tcp_listen_stats_leak.rb +2 -2
- data/test/test_linux_ipv6.rb +8 -0
- data/test/test_raindrops.rb +1 -1
- data/test/{test_linux_tcp_info.rb → test_tcp_info.rb} +34 -14
- data/test/test_watcher.rb +15 -10
- metadata +59 -171
- data/.wrongdoc.yml +0 -6
- data/Rakefile +0 -28
- data/ext/raindrops/linux_tcp_info.c +0 -173
data/ext/raindrops/raindrops.c
CHANGED
@@ -38,7 +38,7 @@ struct raindrops {
|
|
38
38
|
};
|
39
39
|
|
40
40
|
/* called by GC */
|
41
|
-
static void
|
41
|
+
static void rd_free(void *ptr)
|
42
42
|
{
|
43
43
|
struct raindrops *r = ptr;
|
44
44
|
|
@@ -51,11 +51,24 @@ static void gcfree(void *ptr)
|
|
51
51
|
xfree(ptr);
|
52
52
|
}
|
53
53
|
|
54
|
+
static size_t rd_memsize(const void *ptr)
|
55
|
+
{
|
56
|
+
const struct raindrops *r = ptr;
|
57
|
+
|
58
|
+
return r->drops == MAP_FAILED ? 0 : raindrop_size * r->capa;
|
59
|
+
}
|
60
|
+
|
61
|
+
static const rb_data_type_t rd_type = {
|
62
|
+
"raindrops",
|
63
|
+
{ NULL, rd_free, rd_memsize, /* reserved */ },
|
64
|
+
/* parent, data, [ flags ] */
|
65
|
+
};
|
66
|
+
|
54
67
|
/* automatically called at creation (before initialize) */
|
55
68
|
static VALUE alloc(VALUE klass)
|
56
69
|
{
|
57
70
|
struct raindrops *r;
|
58
|
-
VALUE rv =
|
71
|
+
VALUE rv = TypedData_Make_Struct(klass, struct raindrops, &rd_type, r);
|
59
72
|
|
60
73
|
r->drops = MAP_FAILED;
|
61
74
|
return rv;
|
@@ -65,7 +78,7 @@ static struct raindrops *get(VALUE self)
|
|
65
78
|
{
|
66
79
|
struct raindrops *r;
|
67
80
|
|
68
|
-
|
81
|
+
TypedData_Get_Struct(self, struct raindrops, &rd_type, r);
|
69
82
|
|
70
83
|
if (r->drops == MAP_FAILED)
|
71
84
|
rb_raise(rb_eStandardError, "invalid or freed Raindrops");
|
@@ -104,7 +117,9 @@ retry:
|
|
104
117
|
r->drops = mmap(NULL, tmp,
|
105
118
|
PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
|
106
119
|
if (r->drops == MAP_FAILED) {
|
107
|
-
|
120
|
+
int err = errno;
|
121
|
+
|
122
|
+
if ((err == EAGAIN || err == ENOMEM) && tries-- > 0) {
|
108
123
|
rb_gc();
|
109
124
|
goto retry;
|
110
125
|
}
|
@@ -140,7 +155,9 @@ static void resize(struct raindrops *r, size_t new_rd_size)
|
|
140
155
|
|
141
156
|
rv = mremap(old_address, old_size, new_size, MREMAP_MAYMOVE);
|
142
157
|
if (rv == MAP_FAILED) {
|
143
|
-
|
158
|
+
int err = errno;
|
159
|
+
|
160
|
+
if (err == EAGAIN || err == ENOMEM) {
|
144
161
|
rb_gc();
|
145
162
|
rv = mremap(old_address, old_size, new_size, 0);
|
146
163
|
}
|
@@ -323,7 +340,9 @@ static VALUE aref(VALUE self, VALUE index)
|
|
323
340
|
|
324
341
|
#ifdef __linux__
|
325
342
|
void Init_raindrops_linux_inet_diag(void);
|
326
|
-
|
343
|
+
#endif
|
344
|
+
#ifdef HAVE_TYPE_STRUCT_TCP_INFO
|
345
|
+
void Init_raindrops_tcp_info(void);
|
327
346
|
#endif
|
328
347
|
|
329
348
|
#ifndef _SC_NPROCESSORS_CONF
|
@@ -428,6 +447,8 @@ void Init_raindrops_ext(void)
|
|
428
447
|
|
429
448
|
#ifdef __linux__
|
430
449
|
Init_raindrops_linux_inet_diag();
|
431
|
-
|
450
|
+
#endif
|
451
|
+
#ifdef HAVE_TYPE_STRUCT_TCP_INFO
|
452
|
+
Init_raindrops_tcp_info();
|
432
453
|
#endif
|
433
454
|
}
|
@@ -0,0 +1,245 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <sys/socket.h>
|
3
|
+
#include <netinet/in.h>
|
4
|
+
#if defined(HAVE_LINUX_TCP_H)
|
5
|
+
# include <linux/tcp.h>
|
6
|
+
#else
|
7
|
+
# if defined(HAVE_NETINET_TCP_H)
|
8
|
+
# include <netinet/tcp.h>
|
9
|
+
# endif
|
10
|
+
# if defined(HAVE_NETINET_TCP_FSM_H)
|
11
|
+
# include <netinet/tcp_fsm.h>
|
12
|
+
# endif
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifdef HAVE_TYPE_STRUCT_TCP_INFO
|
16
|
+
#include "my_fileno.h"
|
17
|
+
|
18
|
+
CFUNC_tcp_info_tcpi_state
|
19
|
+
CFUNC_tcp_info_tcpi_ca_state
|
20
|
+
CFUNC_tcp_info_tcpi_retransmits
|
21
|
+
CFUNC_tcp_info_tcpi_probes
|
22
|
+
CFUNC_tcp_info_tcpi_backoff
|
23
|
+
CFUNC_tcp_info_tcpi_options
|
24
|
+
CFUNC_tcp_info_tcpi_snd_wscale
|
25
|
+
CFUNC_tcp_info_tcpi_rcv_wscale
|
26
|
+
CFUNC_tcp_info_tcpi_rto
|
27
|
+
CFUNC_tcp_info_tcpi_ato
|
28
|
+
CFUNC_tcp_info_tcpi_snd_mss
|
29
|
+
CFUNC_tcp_info_tcpi_rcv_mss
|
30
|
+
CFUNC_tcp_info_tcpi_unacked
|
31
|
+
CFUNC_tcp_info_tcpi_sacked
|
32
|
+
CFUNC_tcp_info_tcpi_lost
|
33
|
+
CFUNC_tcp_info_tcpi_retrans
|
34
|
+
CFUNC_tcp_info_tcpi_fackets
|
35
|
+
CFUNC_tcp_info_tcpi_last_data_sent
|
36
|
+
CFUNC_tcp_info_tcpi_last_ack_sent
|
37
|
+
CFUNC_tcp_info_tcpi_last_data_recv
|
38
|
+
CFUNC_tcp_info_tcpi_last_ack_recv
|
39
|
+
CFUNC_tcp_info_tcpi_pmtu
|
40
|
+
CFUNC_tcp_info_tcpi_rcv_ssthresh
|
41
|
+
CFUNC_tcp_info_tcpi_rtt
|
42
|
+
CFUNC_tcp_info_tcpi_rttvar
|
43
|
+
CFUNC_tcp_info_tcpi_snd_ssthresh
|
44
|
+
CFUNC_tcp_info_tcpi_snd_cwnd
|
45
|
+
CFUNC_tcp_info_tcpi_advmss
|
46
|
+
CFUNC_tcp_info_tcpi_reordering
|
47
|
+
CFUNC_tcp_info_tcpi_rcv_rtt
|
48
|
+
CFUNC_tcp_info_tcpi_rcv_space
|
49
|
+
CFUNC_tcp_info_tcpi_total_retrans
|
50
|
+
|
51
|
+
static size_t tcpi_memsize(const void *ptr)
|
52
|
+
{
|
53
|
+
return sizeof(struct tcp_info);
|
54
|
+
}
|
55
|
+
|
56
|
+
static const rb_data_type_t tcpi_type = {
|
57
|
+
"tcp_info",
|
58
|
+
{ NULL, RUBY_TYPED_DEFAULT_FREE, tcpi_memsize, /* reserved */ },
|
59
|
+
/* parent, data, [ flags ] */
|
60
|
+
};
|
61
|
+
|
62
|
+
static VALUE alloc(VALUE klass)
|
63
|
+
{
|
64
|
+
struct tcp_info *info;
|
65
|
+
|
66
|
+
return TypedData_Make_Struct(klass, struct tcp_info, &tcpi_type, info);
|
67
|
+
}
|
68
|
+
|
69
|
+
/*
|
70
|
+
* call-seq:
|
71
|
+
*
|
72
|
+
* Raindrops::TCP_Info.new(tcp_socket) -> TCP_Info object
|
73
|
+
*
|
74
|
+
* Reads a TCP_Info object from any given +tcp_socket+. See the tcp(7)
|
75
|
+
* manpage and /usr/include/linux/tcp.h for more details.
|
76
|
+
*/
|
77
|
+
static VALUE init(VALUE self, VALUE io)
|
78
|
+
{
|
79
|
+
int fd = my_fileno(io);
|
80
|
+
struct tcp_info *info = DATA_PTR(self);
|
81
|
+
socklen_t len = (socklen_t)sizeof(struct tcp_info);
|
82
|
+
int rc = getsockopt(fd, IPPROTO_TCP, TCP_INFO, info, &len);
|
83
|
+
|
84
|
+
if (rc != 0)
|
85
|
+
rb_sys_fail("getsockopt");
|
86
|
+
|
87
|
+
return self;
|
88
|
+
}
|
89
|
+
|
90
|
+
void Init_raindrops_tcp_info(void)
|
91
|
+
{
|
92
|
+
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
|
93
|
+
VALUE cTCP_Info;
|
94
|
+
|
95
|
+
/*
|
96
|
+
* Document-class: Raindrops::TCP_Info
|
97
|
+
*
|
98
|
+
* This is used to wrap "struct tcp_info" as described in tcp(7)
|
99
|
+
* and /usr/include/linux/tcp.h. The following readers methods
|
100
|
+
* are defined corresponding to the "tcpi_" fields in the
|
101
|
+
* tcp_info struct.
|
102
|
+
*
|
103
|
+
* As of raindrops 0.18.0+, this is supported on FreeBSD and OpenBSD
|
104
|
+
* systems as well as Linux, although not all fields exist or
|
105
|
+
* match the documentation, below.
|
106
|
+
*
|
107
|
+
* In particular, the +last_data_recv+ field is useful for measuring
|
108
|
+
* the amount of time a client spent in the listen queue before
|
109
|
+
* +accept()+, but only if +TCP_DEFER_ACCEPT+ is used with the
|
110
|
+
* listen socket (it is on by default in Unicorn).
|
111
|
+
*
|
112
|
+
* - state
|
113
|
+
* - ca_state
|
114
|
+
* - retransmits
|
115
|
+
* - probes
|
116
|
+
* - backoff
|
117
|
+
* - options
|
118
|
+
* - snd_wscale
|
119
|
+
* - rcv_wscale
|
120
|
+
* - rto
|
121
|
+
* - ato
|
122
|
+
* - snd_mss
|
123
|
+
* - rcv_mss
|
124
|
+
* - unacked
|
125
|
+
* - sacked
|
126
|
+
* - lost
|
127
|
+
* - retrans
|
128
|
+
* - fackets
|
129
|
+
* - last_data_sent
|
130
|
+
* - last_ack_sent
|
131
|
+
* - last_data_recv
|
132
|
+
* - last_ack_recv
|
133
|
+
* - pmtu
|
134
|
+
* - rcv_ssthresh
|
135
|
+
* - rtt
|
136
|
+
* - rttvar
|
137
|
+
* - snd_ssthresh
|
138
|
+
* - snd_cwnd
|
139
|
+
* - advmss
|
140
|
+
* - reordering
|
141
|
+
* - rcv_rtt
|
142
|
+
* - rcv_space
|
143
|
+
* - total_retrans
|
144
|
+
*
|
145
|
+
* https://kernel.org/doc/man-pages/online/pages/man7/tcp.7.html
|
146
|
+
*/
|
147
|
+
cTCP_Info = rb_define_class_under(cRaindrops, "TCP_Info", rb_cObject);
|
148
|
+
rb_define_alloc_func(cTCP_Info, alloc);
|
149
|
+
rb_define_private_method(cTCP_Info, "initialize", init, 1);
|
150
|
+
|
151
|
+
/*
|
152
|
+
* Document-method: Raindrops::TCP_Info#get!
|
153
|
+
*
|
154
|
+
* call-seq:
|
155
|
+
*
|
156
|
+
* info = Raindrops::TCP_Info.new(tcp_socket)
|
157
|
+
* info.get!(tcp_socket)
|
158
|
+
*
|
159
|
+
* Update an existing TCP_Info objects with the latest stats
|
160
|
+
* from the given socket. This even allows sharing TCP_Info
|
161
|
+
* objects between different sockets to avoid garbage.
|
162
|
+
*/
|
163
|
+
rb_define_method(cTCP_Info, "get!", init, 1);
|
164
|
+
|
165
|
+
DEFINE_METHOD_tcp_info_tcpi_state;
|
166
|
+
DEFINE_METHOD_tcp_info_tcpi_ca_state;
|
167
|
+
DEFINE_METHOD_tcp_info_tcpi_retransmits;
|
168
|
+
DEFINE_METHOD_tcp_info_tcpi_probes;
|
169
|
+
DEFINE_METHOD_tcp_info_tcpi_backoff;
|
170
|
+
DEFINE_METHOD_tcp_info_tcpi_options;
|
171
|
+
DEFINE_METHOD_tcp_info_tcpi_snd_wscale;
|
172
|
+
DEFINE_METHOD_tcp_info_tcpi_rcv_wscale;
|
173
|
+
DEFINE_METHOD_tcp_info_tcpi_rto;
|
174
|
+
DEFINE_METHOD_tcp_info_tcpi_ato;
|
175
|
+
DEFINE_METHOD_tcp_info_tcpi_snd_mss;
|
176
|
+
DEFINE_METHOD_tcp_info_tcpi_rcv_mss;
|
177
|
+
DEFINE_METHOD_tcp_info_tcpi_unacked;
|
178
|
+
DEFINE_METHOD_tcp_info_tcpi_sacked;
|
179
|
+
DEFINE_METHOD_tcp_info_tcpi_lost;
|
180
|
+
DEFINE_METHOD_tcp_info_tcpi_retrans;
|
181
|
+
DEFINE_METHOD_tcp_info_tcpi_fackets;
|
182
|
+
DEFINE_METHOD_tcp_info_tcpi_last_data_sent;
|
183
|
+
DEFINE_METHOD_tcp_info_tcpi_last_ack_sent;
|
184
|
+
DEFINE_METHOD_tcp_info_tcpi_last_data_recv;
|
185
|
+
DEFINE_METHOD_tcp_info_tcpi_last_ack_recv;
|
186
|
+
DEFINE_METHOD_tcp_info_tcpi_pmtu;
|
187
|
+
DEFINE_METHOD_tcp_info_tcpi_rcv_ssthresh;
|
188
|
+
DEFINE_METHOD_tcp_info_tcpi_rtt;
|
189
|
+
DEFINE_METHOD_tcp_info_tcpi_rttvar;
|
190
|
+
DEFINE_METHOD_tcp_info_tcpi_snd_ssthresh;
|
191
|
+
DEFINE_METHOD_tcp_info_tcpi_snd_cwnd;
|
192
|
+
DEFINE_METHOD_tcp_info_tcpi_advmss;
|
193
|
+
DEFINE_METHOD_tcp_info_tcpi_reordering;
|
194
|
+
DEFINE_METHOD_tcp_info_tcpi_rcv_rtt;
|
195
|
+
DEFINE_METHOD_tcp_info_tcpi_rcv_space;
|
196
|
+
DEFINE_METHOD_tcp_info_tcpi_total_retrans;
|
197
|
+
|
198
|
+
#ifdef RAINDROPS_TCP_STATES_ALL_KNOWN
|
199
|
+
|
200
|
+
/*
|
201
|
+
* Document-const: Raindrops::TCP
|
202
|
+
*
|
203
|
+
* This is a frozen hash storing the numeric values
|
204
|
+
* maps platform-independent symbol keys to
|
205
|
+
* platform-dependent numeric values. These states
|
206
|
+
* are all valid values for the Raindrops::TCP_Info#state field.
|
207
|
+
*
|
208
|
+
* The platform-independent names of the keys in this hash are:
|
209
|
+
*
|
210
|
+
* - :ESTABLISHED
|
211
|
+
* - :SYN_SENT
|
212
|
+
* - :SYN_RECV
|
213
|
+
* - :FIN_WAIT1
|
214
|
+
* - :FIN_WAIT2
|
215
|
+
* - :TIME_WAIT
|
216
|
+
* - :CLOSE
|
217
|
+
* - :CLOSE_WAIT
|
218
|
+
* - :LAST_ACK
|
219
|
+
* - :LISTEN
|
220
|
+
* - :CLOSING
|
221
|
+
*
|
222
|
+
* This is only supported on platforms where TCP_Info is supported,
|
223
|
+
* currently FreeBSD, OpenBSD, and Linux-based systems.
|
224
|
+
*/
|
225
|
+
{
|
226
|
+
#define TCPSET(n,v) rb_hash_aset(tcp, ID2SYM(rb_intern(#n)), INT2NUM(v))
|
227
|
+
VALUE tcp = rb_hash_new();
|
228
|
+
TCPSET(ESTABLISHED, RAINDROPS_TCP_ESTABLISHED);
|
229
|
+
TCPSET(SYN_SENT, RAINDROPS_TCP_SYN_SENT);
|
230
|
+
TCPSET(SYN_RECV, RAINDROPS_TCP_SYN_RECV);
|
231
|
+
TCPSET(FIN_WAIT1, RAINDROPS_TCP_FIN_WAIT1);
|
232
|
+
TCPSET(FIN_WAIT2, RAINDROPS_TCP_FIN_WAIT2);
|
233
|
+
TCPSET(TIME_WAIT, RAINDROPS_TCP_TIME_WAIT);
|
234
|
+
TCPSET(CLOSE, RAINDROPS_TCP_CLOSE);
|
235
|
+
TCPSET(CLOSE_WAIT, RAINDROPS_TCP_CLOSE_WAIT);
|
236
|
+
TCPSET(LAST_ACK, RAINDROPS_TCP_LAST_ACK);
|
237
|
+
TCPSET(LISTEN, RAINDROPS_TCP_LISTEN);
|
238
|
+
TCPSET(CLOSING, RAINDROPS_TCP_CLOSING);
|
239
|
+
#undef TCPSET
|
240
|
+
OBJ_FREEZE(tcp);
|
241
|
+
rb_define_const(cRaindrops, "TCP", tcp);
|
242
|
+
}
|
243
|
+
#endif
|
244
|
+
}
|
245
|
+
#endif /* HAVE_STRUCT_TCP_INFO */
|
data/lib/raindrops.rb
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
# Unlike many classes in this package, the core Raindrops class is
|
13
13
|
# intended to be portable to all reasonably modern *nix systems
|
14
14
|
# supporting mmap(). Please let us know if you have portability
|
15
|
-
# issues, patches or pull requests at mailto:raindrops@
|
15
|
+
# issues, patches or pull requests at mailto:raindrops-public@yhbt.net
|
16
16
|
class Raindrops
|
17
17
|
|
18
18
|
# Used to represent the number of +active+ and +queued+ sockets for
|
data/lib/raindrops/aggregate.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
#
|
3
|
-
# raindrops may use the {aggregate}[
|
3
|
+
# raindrops may use the {aggregate}[https://github.com/josephruscio/aggregate]
|
4
4
|
# RubyGem to aggregate statistics from TCP_Info lookups.
|
5
5
|
module Raindrops::Aggregate
|
6
6
|
autoload :PMQ, "raindrops/aggregate/pmq"
|
@@ -13,10 +13,6 @@
|
|
13
13
|
# - Kgio::TCPServer#kgio_accept
|
14
14
|
# - Kgio::TCPServer#kgio_tryaccept
|
15
15
|
module Raindrops::Aggregate::LastDataRecv
|
16
|
-
# :stopdoc:
|
17
|
-
TCP_Info = Raindrops::TCP_Info
|
18
|
-
# :startdoc:
|
19
|
-
|
20
16
|
# The integer value of +last_data_recv+ is sent to this object.
|
21
17
|
# This is usually a duck type compatible with the \Aggregate class,
|
22
18
|
# but can be *anything* that accepts the *<<* method.
|
@@ -78,7 +74,7 @@ def accept_nonblock
|
|
78
74
|
# +last_data_recv+ to be accurate
|
79
75
|
def count!(io)
|
80
76
|
if io
|
81
|
-
x = TCP_Info.new(io)
|
77
|
+
x = Raindrops::TCP_Info.new(io)
|
82
78
|
@raindrops_aggregate << x.last_data_recv
|
83
79
|
end
|
84
80
|
io
|
@@ -3,10 +3,10 @@
|
|
3
3
|
require "aggregate"
|
4
4
|
require "posix_mq"
|
5
5
|
require "fcntl"
|
6
|
-
require "io/extra"
|
7
6
|
require "thread"
|
7
|
+
require "stringio"
|
8
8
|
|
9
|
-
# \Aggregate + POSIX message queues support for Ruby 1.9 and \Linux
|
9
|
+
# \Aggregate + POSIX message queues support for Ruby 1.9+ and \Linux
|
10
10
|
#
|
11
11
|
# This class is duck-type compatible with \Aggregate and allows us to
|
12
12
|
# aggregate and share statistics from multiple processes/threads aided
|
@@ -14,12 +14,11 @@
|
|
14
14
|
# Raindrops::LastDataRecv Rack application, but can be used independently
|
15
15
|
# on compatible Runtimes.
|
16
16
|
#
|
17
|
-
# Unlike the core of raindrops, this is only supported on Ruby 1.9 and
|
18
|
-
# Linux 2.6
|
17
|
+
# Unlike the core of raindrops, this is only supported on Ruby 1.9+ and
|
18
|
+
# Linux 2.6+. Using this class requires the following additional RubyGems
|
19
19
|
# or libraries:
|
20
20
|
#
|
21
21
|
# * aggregate (tested with 0.2.2)
|
22
|
-
# * io-extra (tested with 1.2.3)
|
23
22
|
# * posix_mq (tested with 1.0.0)
|
24
23
|
#
|
25
24
|
# == Design
|
@@ -39,9 +38,9 @@ class Raindrops::Aggregate::PMQ
|
|
39
38
|
# :stopdoc:
|
40
39
|
# These constants are for Linux. This is designed for aggregating
|
41
40
|
# TCP_INFO.
|
42
|
-
RDLOCK = [ Fcntl::F_RDLCK ].pack("s @256")
|
43
|
-
WRLOCK = [ Fcntl::F_WRLCK ].pack("s @256")
|
44
|
-
UNLOCK = [ Fcntl::F_UNLCK ].pack("s @256")
|
41
|
+
RDLOCK = [ Fcntl::F_RDLCK ].pack("s @256".freeze).freeze
|
42
|
+
WRLOCK = [ Fcntl::F_WRLCK ].pack("s @256".freeze).freeze
|
43
|
+
UNLOCK = [ Fcntl::F_UNLCK ].pack("s @256".freeze).freeze
|
45
44
|
# :startdoc:
|
46
45
|
|
47
46
|
# returns the number of dropped messages sent to a POSIX message
|
@@ -84,6 +83,7 @@ def initialize(params = {})
|
|
84
83
|
@wr = File.open(t.path, "wb")
|
85
84
|
@rd = File.open(t.path, "rb")
|
86
85
|
end
|
86
|
+
@wr.sync = true
|
87
87
|
@cached_aggregate = @aggregate
|
88
88
|
flush_master
|
89
89
|
@mq_send = if opts[:lossy]
|
@@ -142,8 +142,8 @@ def master_loop
|
|
142
142
|
warn "Unhandled exception in #{__FILE__}:#{__LINE__}: #{e}"
|
143
143
|
break
|
144
144
|
end while true
|
145
|
-
|
146
|
-
|
145
|
+
ensure
|
146
|
+
flush_master
|
147
147
|
end
|
148
148
|
|
149
149
|
# Loads the last shared \Aggregate from the master thread/process
|
@@ -151,7 +151,10 @@ def aggregate
|
|
151
151
|
@cached_aggregate ||= begin
|
152
152
|
flush
|
153
153
|
Marshal.load(synchronize(@rd, RDLOCK) do |rd|
|
154
|
-
|
154
|
+
dst = StringIO.new
|
155
|
+
dst.binmode
|
156
|
+
IO.copy_stream(rd, dst, rd.size, 0)
|
157
|
+
dst.string
|
155
158
|
end)
|
156
159
|
end
|
157
160
|
end
|
@@ -163,7 +166,8 @@ def flush_master
|
|
163
166
|
dump = Marshal.dump @aggregate
|
164
167
|
synchronize(@wr, WRLOCK) do |wr|
|
165
168
|
wr.truncate 0
|
166
|
-
|
169
|
+
wr.rewind
|
170
|
+
wr.write(dump)
|
167
171
|
end
|
168
172
|
end
|
169
173
|
|
@@ -171,24 +175,26 @@ def flush_master
|
|
171
175
|
# worker thread or process
|
172
176
|
def stop_master_loop
|
173
177
|
sleep 0.1 until mq_send(false)
|
174
|
-
|
175
|
-
|
178
|
+
rescue Errno::EINTR
|
179
|
+
retry
|
176
180
|
end
|
177
181
|
|
178
182
|
def lock! io, type # :nodoc:
|
179
183
|
io.fcntl Fcntl::F_SETLKW, type
|
180
|
-
|
181
|
-
|
184
|
+
rescue Errno::EINTR
|
185
|
+
retry
|
182
186
|
end
|
183
187
|
|
184
188
|
# we use both a mutex for thread-safety and fcntl lock for process-safety
|
185
189
|
def synchronize io, type # :nodoc:
|
186
190
|
@mutex.synchronize do
|
187
191
|
begin
|
192
|
+
type = type.dup
|
188
193
|
lock! io, type
|
189
194
|
yield io
|
190
195
|
ensure
|
191
|
-
lock! io, UNLOCK
|
196
|
+
lock! io, type.replace(UNLOCK)
|
197
|
+
type.clear
|
192
198
|
end
|
193
199
|
end
|
194
200
|
end
|