raindrops 0.18.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.olddoc.yml +12 -10
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +1 -1
- data/LATEST +6 -38
- data/NEWS +50 -0
- data/README +16 -16
- data/examples/linux-listener-stats.rb +1 -2
- data/examples/watcher_demo.ru +1 -1
- data/ext/raindrops/extconf.rb +2 -1
- data/ext/raindrops/linux_inet_diag.c +17 -38
- data/ext/raindrops/raindrops.c +48 -15
- data/ext/raindrops/tcp_info.c +0 -1
- data/lib/raindrops/aggregate/pmq.rb +6 -6
- data/lib/raindrops/linux.rb +4 -5
- data/lib/raindrops/middleware/proxy.rb +2 -2
- data/lib/raindrops/middleware.rb +2 -2
- data/lib/raindrops/watcher.rb +7 -7
- data/lib/raindrops.rb +25 -1
- data/pkg.mk +3 -2
- data/raindrops.gemspec +2 -2
- data/test/ipv6_enabled.rb +4 -4
- data/test/test_linux.rb +3 -2
- data/test/test_linux_all_tcp_listen_stats_leak.rb +2 -2
- data/test/test_raindrops.rb +43 -1
- data/test/test_tcp_info.rb +4 -4
- data/test/test_watcher.rb +9 -9
- metadata +5 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6f78e29ec57e3f3710146a423cf60915d23a5f4366d70dcabbbef74fb69f71f3
|
4
|
+
data.tar.gz: 8a369d49c33a67af3b6acccaf64b04ed192cba9d163c8d48944cfac887511885
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b9e5de8e7a7a84038bbe19a954d3d559ebec3ed4c7f68db2e2ada6373b045f4fbcd784c5d5b91005cad1d87f1db93f9dc31c9f7fc59ae56a7f73b98d9a96bf2e
|
7
|
+
data.tar.gz: 9913e9205b2527b9f5bd1bae58b0c2c8962505e87280c06257f603fb722978d6656c99cfa0a297ccd0734a7d6110b0a6ecd5155fec9870ec40a31044a00def4d
|
data/.olddoc.yml
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
---
|
2
|
-
cgit_url: https://
|
3
|
-
|
4
|
-
|
5
|
-
public_email: raindrops-public@bogomips.org
|
2
|
+
cgit_url: https://yhbt.net/raindrops.git/
|
3
|
+
rdoc_url: https://yhbt.net/raindrops/
|
4
|
+
public_email: raindrops-public@yhbt.net
|
6
5
|
ml_url:
|
7
|
-
- https://
|
8
|
-
- http://
|
6
|
+
- https://yhbt.net/raindrops-public/
|
7
|
+
- http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/raindrops-public
|
8
|
+
imap_url:
|
9
|
+
- imaps://yhbt.net/inbox.comp.lang.ruby.raindrops.0
|
10
|
+
- imap://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/inbox.comp.lang.ruby.raindrops.0
|
9
11
|
nntp_url:
|
10
|
-
-
|
11
|
-
- nntp://
|
12
|
+
- nntps://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
|
13
|
+
- nntp://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/inbox.comp.lang.ruby.raindrops
|
12
14
|
source_code:
|
13
|
-
- git clone
|
14
|
-
- git clone
|
15
|
+
- git clone https://yhbt.net/raindrops.git
|
16
|
+
- torsocks git clone http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/raindrops.git
|
data/GIT-VERSION-FILE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
GIT_VERSION = 0.
|
1
|
+
GIT_VERSION = 0.20.0
|
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
data/LATEST
CHANGED
@@ -1,42 +1,10 @@
|
|
1
|
-
=== raindrops 0.
|
1
|
+
=== raindrops 0.20.0 / 2021-12-06 23:41 UTC
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
Raindrops::TCP for portably mapping TCP state names to
|
6
|
-
platform-dependent numeric values:
|
3
|
+
Raindrops may now use file-backed mmap() rather than anonymous
|
4
|
+
memory. Thanks to KJ Tsanaktsidis for the patch:
|
7
5
|
|
8
|
-
|
6
|
+
https://yhbt.net/raindrops-public/20211125065618.3432-1-ktsanaktsidis@zendesk.com/T/
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
these changes to raindrops.
|
13
|
-
|
14
|
-
There's also a few internal cleanups, and documentation
|
15
|
-
improvements, including some fixes to the largely-forgotten
|
16
|
-
Raindrops::Aggreage::PMQ class:
|
17
|
-
|
18
|
-
https://bogomips.org/raindrops/Raindrops/Aggregate/PMQ.html
|
19
|
-
|
20
|
-
20 changes since 0.17.0:
|
21
|
-
|
22
|
-
test_inet_diag_socket: fix Fixnum deprecation warning
|
23
|
-
TODO: add item for IPv6 breakage
|
24
|
-
ext: fix documentation for C ext-defined classes
|
25
|
-
TCP_Info: custom documentation for #get!
|
26
|
-
TypedData C-API conversion
|
27
|
-
test_watcher: disable test correctly when aggregate is missing
|
28
|
-
tcp_info: support this struct under FreeBSD
|
29
|
-
define Raindrops::TCP hash for TCP states
|
30
|
-
linux_inet_diag: reduce stack usage and simplify
|
31
|
-
avoid reading errno repeatedly
|
32
|
-
aggregate/pmq: avoid false sharing of lock buffers
|
33
|
-
aggregate/pmq: remove io-extra requirement
|
34
|
-
aggregate/pmq: avoid File#stat allocation
|
35
|
-
Merge remote-tracking branch 'origin/freebsd'
|
36
|
-
Merge remote-tracking branch 'origin/aggregate-pmq'
|
37
|
-
doc: remove private email support address
|
38
|
-
doc: update location of TCP_INFO-related stuff
|
39
|
-
build: avoid olddoc for building the RubyGem
|
40
|
-
doc: document Raindrops::TCP hash
|
41
|
-
aggregate/pmq: update version numbers for Ruby and Linux
|
8
|
+
The documentation is also updated to note our mail archives are now
|
9
|
+
available via IMAP(S).
|
42
10
|
|
data/NEWS
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
=== raindrops 0.20.0 / 2021-12-06 23:41 UTC
|
2
|
+
|
3
|
+
Raindrops may now use file-backed mmap() rather than anonymous
|
4
|
+
memory. Thanks to KJ Tsanaktsidis for the patch:
|
5
|
+
|
6
|
+
https://yhbt.net/raindrops-public/20211125065618.3432-1-ktsanaktsidis@zendesk.com/T/
|
7
|
+
|
8
|
+
The documentation is also updated to note our mail archives are now
|
9
|
+
available via IMAP(S).
|
10
|
+
|
11
|
+
=== raindrops 0.19.2 / 2021-05-25 23:13 UTC
|
12
|
+
|
13
|
+
This release fixes compatibility with GC.compact on Ruby 3.x
|
14
|
+
when using ListenStats on Linux. The listener stats
|
15
|
+
functionality is rarely used and does not affect most users
|
16
|
+
who just have raindrops installed for shared atomic counters.
|
17
|
+
|
18
|
+
=== raindrops 0.19.1 / 2020-01-08 09:31 UTC
|
19
|
+
|
20
|
+
This release fixes some warnings on newer Rubies.
|
21
|
+
|
22
|
+
We're no longer on bogomips.org since it's due
|
23
|
+
for expiry and I can't pay extortionists for a .org, so
|
24
|
+
s/bogomips.org/yhbt.net/ for now, and be prepared to move again
|
25
|
+
when extortionists move onto extorting the .net TLD.
|
26
|
+
|
27
|
+
doc: switch homepage to dark216
|
28
|
+
ext/raindrops/extconf: fix cflags reset on ancient CC
|
29
|
+
fixes for newer rubies
|
30
|
+
replace bogomips.org with yhbt.net
|
31
|
+
|
32
|
+
=== raindrops 0.19.0 - Rack 2.x middleware compatibility / 2017-08-09 23:52 UTC
|
33
|
+
|
34
|
+
This release fixes Rack 2.x compatibility for the few users of
|
35
|
+
Raindrops::Middleware
|
36
|
+
<https://bogomips.org/raindrops/Raindrops/Middleware.html>.
|
37
|
+
Thanks to Dmytro Shteflyuk for this release.
|
38
|
+
|
39
|
+
No need to upgrade unless you use Raindrops::Middleware with
|
40
|
+
Rack 2.x.
|
41
|
+
|
42
|
+
There's also a few minor, inconsequential cleanups.
|
43
|
+
|
44
|
+
Dmytro Shteflyuk (1):
|
45
|
+
Properly override respond_to? in Raindrops::Middleware::Proxy
|
46
|
+
|
47
|
+
Eric Wong (2):
|
48
|
+
Ruby thread compatibility updates
|
49
|
+
tcp_info: remove unnecessary extconf.h include
|
50
|
+
|
1
51
|
=== raindrops 0.18.0 / 2017-03-23 02:44 UTC
|
2
52
|
|
3
53
|
The most notable feature of this release is the addition of
|
data/README
CHANGED
@@ -58,24 +58,20 @@ If you use RubyGems:
|
|
58
58
|
|
59
59
|
See Raindrops::Middleware and Raindrops::LastDataRecv documentation for
|
60
60
|
use Rack servers. The entire library is fully-documented and we are
|
61
|
-
responsive on the
|
62
|
-
(mailto:raindrops-public@
|
63
|
-
you have any questions or comments.
|
61
|
+
responsive on the publicly archived mailbox
|
62
|
+
(mailto:raindrops-public@yhbt.net) if you have any questions or comments.
|
64
63
|
|
65
64
|
== Development
|
66
65
|
|
67
66
|
You can get the latest source via git from the following locations:
|
68
67
|
|
69
|
-
|
70
|
-
|
68
|
+
https://yhbt.net/raindrops.git
|
69
|
+
http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/raindrops.git
|
70
|
+
http://repo.or.cz/w/raindrops.git (gitweb mirror)
|
71
71
|
|
72
|
-
|
73
|
-
tarballs here:
|
72
|
+
Snapshots and tarballs are available.
|
74
73
|
|
75
|
-
|
76
|
-
* http://repo.or.cz/w/raindrops.git (gitweb)
|
77
|
-
|
78
|
-
Inline patches (from "git format-patch") to the mailing list are
|
74
|
+
Inline patches (from "git format-patch") to the mailbox are
|
79
75
|
preferred because they allow code review and comments in the reply to
|
80
76
|
the patch.
|
81
77
|
|
@@ -89,13 +85,17 @@ raindrops is licensed under the LGPL-2.1+
|
|
89
85
|
== Contact
|
90
86
|
|
91
87
|
All feedback (bug reports, user/development discussion, patches, pull
|
92
|
-
requests) go to the
|
93
|
-
mailto:raindrops-public@
|
88
|
+
requests) go to the publicly archived mailbox:
|
89
|
+
mailto:raindrops-public@yhbt.net
|
94
90
|
|
95
|
-
|
91
|
+
Mail archives are available over HTTP(S), IMAP(S) and NNTP(S):
|
96
92
|
|
97
|
-
* https://
|
98
|
-
*
|
93
|
+
* https://yhbt.net/raindrops-public/
|
94
|
+
* http://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/raindrops-public/
|
95
|
+
* imaps://yhbt.net/inbox.comp.lang.ruby.raindrops.0
|
96
|
+
* imap://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/inbox.comp.lang.ruby.raindrops.0
|
97
|
+
* nntps://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
|
98
|
+
* nntp://7fh6tueqddpjyxjmgtdiueylzoqt6pt7hec3pukyptlmohoowvhde4yd.onion/inbox.comp.lang.ruby.raindrops
|
99
99
|
|
100
100
|
Since archives are public, scrub sensitive information and
|
101
101
|
use anonymity tools such as Tor or Mixmaster if you deem necessary.
|
@@ -15,7 +15,6 @@ end
|
|
15
15
|
usage = "Usage: #$0 [-d DELAY] [-t QUEUED_THRESHOLD] ADDR..."
|
16
16
|
ARGV.size > 0 or abort usage
|
17
17
|
delay = false
|
18
|
-
all = false
|
19
18
|
queued_thresh = -1
|
20
19
|
# "normal" exits when driven on the command-line
|
21
20
|
trap(:INT) { exit 130 }
|
@@ -25,7 +24,7 @@ OptionParser.new('', 24, ' ') do |opts|
|
|
25
24
|
opts.banner = usage
|
26
25
|
opts.on('-d', '--delay=DELAY', Float) { |n| delay = n }
|
27
26
|
opts.on('-t', '--queued-threshold=INT', Integer) { |n| queued_thresh = n }
|
28
|
-
opts.on('-a', '--all') {
|
27
|
+
opts.on('-a', '--all') { } # noop
|
29
28
|
opts.parse! ARGV
|
30
29
|
end
|
31
30
|
|
data/examples/watcher_demo.ru
CHANGED
data/ext/raindrops/extconf.rb
CHANGED
@@ -112,6 +112,7 @@ EOF
|
|
112
112
|
end
|
113
113
|
|
114
114
|
have_func("getpagesize", "unistd.h")
|
115
|
+
have_func('rb_thread_call_without_gvl')
|
115
116
|
have_func('rb_thread_blocking_region')
|
116
117
|
have_func('rb_thread_io_blocking_region')
|
117
118
|
|
@@ -142,7 +143,7 @@ SRC
|
|
142
143
|
$defs.push(format("-DHAVE_GCC_ATOMIC_BUILTINS"))
|
143
144
|
true
|
144
145
|
else
|
145
|
-
|
146
|
+
$CFLAGS = prev_cflags
|
146
147
|
false
|
147
148
|
end
|
148
149
|
end
|
@@ -1,46 +1,24 @@
|
|
1
1
|
#include <ruby.h>
|
2
2
|
#include <stdarg.h>
|
3
|
-
#
|
4
|
-
# include <ruby/st.h>
|
5
|
-
#else
|
6
|
-
# include <st.h>
|
7
|
-
#endif
|
3
|
+
#include <ruby/st.h>
|
8
4
|
#include "my_fileno.h"
|
9
5
|
#ifdef __linux__
|
10
6
|
|
11
|
-
/* Ruby 1.8.6+ macros (for compatibility with Ruby 1.9) */
|
12
|
-
#ifndef RSTRING_LEN
|
13
|
-
# define RSTRING_LEN(s) (RSTRING(s)->len)
|
14
|
-
#endif
|
15
|
-
|
16
|
-
/* partial emulation of the 1.9 rb_thread_blocking_region under 1.8 */
|
17
|
-
#if !defined(HAVE_RB_THREAD_BLOCKING_REGION) && \
|
18
|
-
!defined(HAVE_RB_THREAD_IO_BLOCKING_REGION)
|
19
|
-
# include <rubysig.h>
|
20
|
-
# define RUBY_UBF_IO ((rb_unblock_function_t *)-1)
|
21
|
-
typedef void rb_unblock_function_t(void *);
|
22
|
-
typedef VALUE rb_blocking_function_t(void *);
|
23
|
-
static VALUE
|
24
|
-
rb_thread_blocking_region(
|
25
|
-
rb_blocking_function_t *func, void *data1,
|
26
|
-
rb_unblock_function_t *ubf, void *data2)
|
27
|
-
{
|
28
|
-
VALUE rv;
|
29
|
-
|
30
|
-
TRAP_BEG;
|
31
|
-
rv = func(data1);
|
32
|
-
TRAP_END;
|
33
|
-
|
34
|
-
return rv;
|
35
|
-
}
|
36
|
-
#endif /* ! HAVE_RB_THREAD_BLOCKING_REGION */
|
37
|
-
|
38
7
|
#ifdef HAVE_RB_THREAD_IO_BLOCKING_REGION
|
8
|
+
/* Ruby 1.9.3 and 2.0.0 */
|
39
9
|
VALUE rb_thread_io_blocking_region(rb_blocking_function_t *, void *, int);
|
10
|
+
# define rd_fd_region(fn,data,fd) \
|
11
|
+
rb_thread_io_blocking_region((fn),(data),(fd))
|
12
|
+
#elif defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) && \
|
13
|
+
defined(HAVE_RUBY_THREAD_H) && HAVE_RUBY_THREAD_H
|
14
|
+
/* in case Ruby 2.0+ ever drops rb_thread_io_blocking_region: */
|
15
|
+
# include <ruby/thread.h>
|
16
|
+
# define COMPAT_FN (void *(*)(void *))
|
17
|
+
# define rd_fd_region(fn,data,fd) \
|
18
|
+
rb_thread_call_without_gvl(COMPAT_FN(fn),(data),RUBY_UBF_IO,NULL)
|
40
19
|
#else
|
41
|
-
#
|
42
|
-
|
43
|
-
#endif /* HAVE_RB_THREAD_IO_BLOCKING_REGION */
|
20
|
+
# error Ruby <= 1.8 not supported
|
21
|
+
#endif
|
44
22
|
|
45
23
|
#include <assert.h>
|
46
24
|
#include <errno.h>
|
@@ -227,7 +205,7 @@ static void bug_warn_nogvl(const char *fmt, ...)
|
|
227
205
|
va_end(ap);
|
228
206
|
|
229
207
|
fprintf(stderr, "Please report how you produced this at "\
|
230
|
-
"raindrops-public@
|
208
|
+
"raindrops-public@yhbt.net\n");
|
231
209
|
fflush(stderr);
|
232
210
|
}
|
233
211
|
|
@@ -608,7 +586,7 @@ static VALUE tcp_stats(struct nogvl_args *args, VALUE addr)
|
|
608
586
|
gen_bytecode(&args->iov[2], &query_addr);
|
609
587
|
|
610
588
|
memset(&args->stats, 0, sizeof(struct listen_stats));
|
611
|
-
nl_errcheck(
|
589
|
+
nl_errcheck(rd_fd_region(diag, args, args->fd));
|
612
590
|
|
613
591
|
return rb_listen_stats(&args->stats);
|
614
592
|
}
|
@@ -685,7 +663,7 @@ static VALUE tcp_listener_stats(int argc, VALUE *argv, VALUE self)
|
|
685
663
|
"addr must be an array of strings, a string, or nil");
|
686
664
|
}
|
687
665
|
|
688
|
-
nl_errcheck(
|
666
|
+
nl_errcheck(rd_fd_region(diag, &args, args.fd));
|
689
667
|
|
690
668
|
st_foreach(args.table, NIL_P(addrs) ? st_to_hash : st_AND_hash, rv);
|
691
669
|
st_free_table(args.table);
|
@@ -718,6 +696,7 @@ void Init_raindrops_linux_inet_diag(void)
|
|
718
696
|
rb_define_singleton_method(cIDSock, "new", ids_s_new, 0);
|
719
697
|
|
720
698
|
cListenStats = rb_const_get(cRaindrops, rb_intern("ListenStats"));
|
699
|
+
rb_gc_register_mark_object(cListenStats); /* pin */
|
721
700
|
|
722
701
|
rb_define_module_function(mLinux, "tcp_listener_stats",
|
723
702
|
tcp_listener_stats, -1);
|
data/ext/raindrops/raindrops.c
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#include <assert.h>
|
5
5
|
#include <errno.h>
|
6
6
|
#include <stddef.h>
|
7
|
+
#include <string.h>
|
7
8
|
#include "raindrops_atomic.h"
|
8
9
|
|
9
10
|
#ifndef SIZET2NUM
|
@@ -34,9 +35,17 @@ struct raindrops {
|
|
34
35
|
size_t size;
|
35
36
|
size_t capa;
|
36
37
|
pid_t pid;
|
38
|
+
VALUE io;
|
37
39
|
struct raindrop *drops;
|
38
40
|
};
|
39
41
|
|
42
|
+
/* called by GC */
|
43
|
+
static void rd_mark(void *ptr)
|
44
|
+
{
|
45
|
+
struct raindrops *r = ptr;
|
46
|
+
rb_gc_mark(r->io);
|
47
|
+
}
|
48
|
+
|
40
49
|
/* called by GC */
|
41
50
|
static void rd_free(void *ptr)
|
42
51
|
{
|
@@ -60,7 +69,7 @@ static size_t rd_memsize(const void *ptr)
|
|
60
69
|
|
61
70
|
static const rb_data_type_t rd_type = {
|
62
71
|
"raindrops",
|
63
|
-
{
|
72
|
+
{ rd_mark, rd_free, rd_memsize, /* reserved */ },
|
64
73
|
/* parent, data, [ flags ] */
|
65
74
|
};
|
66
75
|
|
@@ -87,16 +96,10 @@ static struct raindrops *get(VALUE self)
|
|
87
96
|
}
|
88
97
|
|
89
98
|
/*
|
90
|
-
*
|
91
|
-
*
|
92
|
-
*
|
93
|
-
* Initializes a Raindrops object to hold +size+ counters. +size+ is
|
94
|
-
* only a hint and the actual number of counters the object has is
|
95
|
-
* dependent on the CPU model, number of cores, and page size of
|
96
|
-
* the machine. The actual size of the object will always be equal
|
97
|
-
* or greater than the specified +size+.
|
99
|
+
* This is the _actual_ implementation of #initialize - the Ruby wrapper
|
100
|
+
* handles keyword-argument handling then calls this method.
|
98
101
|
*/
|
99
|
-
static VALUE
|
102
|
+
static VALUE init_cimpl(VALUE self, VALUE size, VALUE io, VALUE zero)
|
100
103
|
{
|
101
104
|
struct raindrops *r = DATA_PTR(self);
|
102
105
|
int tries = 1;
|
@@ -113,9 +116,19 @@ static VALUE init(VALUE self, VALUE size)
|
|
113
116
|
r->capa = tmp / raindrop_size;
|
114
117
|
assert(PAGE_ALIGN(raindrop_size * r->capa) == tmp && "not aligned");
|
115
118
|
|
119
|
+
r->io = io;
|
120
|
+
|
116
121
|
retry:
|
117
|
-
r->
|
118
|
-
|
122
|
+
if (RTEST(r->io)) {
|
123
|
+
int fd = NUM2INT(rb_funcall(r->io, rb_intern("fileno"), 0));
|
124
|
+
rb_funcall(r->io, rb_intern("truncate"), 1, SIZET2NUM(tmp));
|
125
|
+
r->drops = mmap(NULL, tmp,
|
126
|
+
PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
127
|
+
} else {
|
128
|
+
r->drops = mmap(NULL, tmp,
|
129
|
+
PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
|
130
|
+
-1, 0);
|
131
|
+
}
|
119
132
|
if (r->drops == MAP_FAILED) {
|
120
133
|
int err = errno;
|
121
134
|
|
@@ -127,6 +140,9 @@ retry:
|
|
127
140
|
}
|
128
141
|
r->pid = getpid();
|
129
142
|
|
143
|
+
if (RTEST(zero))
|
144
|
+
memset(r->drops, 0, tmp);
|
145
|
+
|
130
146
|
return self;
|
131
147
|
}
|
132
148
|
|
@@ -217,14 +233,16 @@ static VALUE capa(VALUE self)
|
|
217
233
|
* call-seq:
|
218
234
|
* rd.dup -> rd_copy
|
219
235
|
*
|
220
|
-
* Duplicates and snapshots the current state of a Raindrops object.
|
236
|
+
* Duplicates and snapshots the current state of a Raindrops object. Even
|
237
|
+
* if the given Raindrops object is backed by a file, the copy will be backed
|
238
|
+
* by independent, anonymously mapped memory.
|
221
239
|
*/
|
222
240
|
static VALUE init_copy(VALUE dest, VALUE source)
|
223
241
|
{
|
224
242
|
struct raindrops *dst = DATA_PTR(dest);
|
225
243
|
struct raindrops *src = get(source);
|
226
244
|
|
227
|
-
|
245
|
+
init_cimpl(dest, SIZET2NUM(src->size), Qnil, Qfalse);
|
228
246
|
memcpy(dst->drops, src->drops, raindrop_size * src->size);
|
229
247
|
|
230
248
|
return dest;
|
@@ -375,6 +393,20 @@ static VALUE evaporate_bang(VALUE self)
|
|
375
393
|
return Qnil;
|
376
394
|
}
|
377
395
|
|
396
|
+
/*
|
397
|
+
* call-seq:
|
398
|
+
* to_io -> IO
|
399
|
+
*
|
400
|
+
* Returns the IO object backing the memory for this raindrop, if
|
401
|
+
* one was specified when constructing this Raindrop. If this
|
402
|
+
* Raindrop is backed by anonymous memory, this method returns nil.
|
403
|
+
*/
|
404
|
+
static VALUE to_io(VALUE self)
|
405
|
+
{
|
406
|
+
struct raindrops *r = get(self);
|
407
|
+
return r->io;
|
408
|
+
}
|
409
|
+
|
378
410
|
void Init_raindrops_ext(void)
|
379
411
|
{
|
380
412
|
VALUE cRaindrops = rb_define_class("Raindrops", rb_cObject);
|
@@ -433,7 +465,7 @@ void Init_raindrops_ext(void)
|
|
433
465
|
|
434
466
|
rb_define_alloc_func(cRaindrops, alloc);
|
435
467
|
|
436
|
-
|
468
|
+
rb_define_private_method(cRaindrops, "initialize_cimpl", init_cimpl, 3);
|
437
469
|
rb_define_method(cRaindrops, "incr", incr, -1);
|
438
470
|
rb_define_method(cRaindrops, "decr", decr, -1);
|
439
471
|
rb_define_method(cRaindrops, "to_ary", to_ary, 0);
|
@@ -444,6 +476,7 @@ void Init_raindrops_ext(void)
|
|
444
476
|
rb_define_method(cRaindrops, "capa", capa, 0);
|
445
477
|
rb_define_method(cRaindrops, "initialize_copy", init_copy, 1);
|
446
478
|
rb_define_method(cRaindrops, "evaporate!", evaporate_bang, 0);
|
479
|
+
rb_define_method(cRaindrops, "to_io", to_io, 0);
|
447
480
|
|
448
481
|
#ifdef __linux__
|
449
482
|
Init_raindrops_linux_inet_diag();
|
data/ext/raindrops/tcp_info.c
CHANGED
@@ -142,8 +142,8 @@ class Raindrops::Aggregate::PMQ
|
|
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
|
@@ -175,14 +175,14 @@ class Raindrops::Aggregate::PMQ
|
|
175
175
|
# worker thread or process
|
176
176
|
def stop_master_loop
|
177
177
|
sleep 0.1 until mq_send(false)
|
178
|
-
|
179
|
-
|
178
|
+
rescue Errno::EINTR
|
179
|
+
retry
|
180
180
|
end
|
181
181
|
|
182
182
|
def lock! io, type # :nodoc:
|
183
183
|
io.fcntl Fcntl::F_SETLKW, type
|
184
|
-
|
185
|
-
|
184
|
+
rescue Errno::EINTR
|
185
|
+
retry
|
186
186
|
end
|
187
187
|
|
188
188
|
# we use both a mutex for thread-safety and fcntl lock for process-safety
|
data/lib/raindrops/linux.rb
CHANGED
@@ -14,8 +14,7 @@ module Raindrops::Linux
|
|
14
14
|
# The standard proc path for active UNIX domain sockets, feel free to call
|
15
15
|
# String#replace on this if your /proc is mounted in a non-standard location
|
16
16
|
# for whatever reason
|
17
|
-
PROC_NET_UNIX_ARGS =
|
18
|
-
defined?(::Encoding) and PROC_NET_UNIX_ARGS.push({ :encoding => "binary" })
|
17
|
+
PROC_NET_UNIX_ARGS = [ '/proc/net/unix', { encoding: "binary" }]
|
19
18
|
|
20
19
|
# Get ListenStats from an array of +paths+
|
21
20
|
#
|
@@ -42,11 +41,11 @@ module Raindrops::Linux
|
|
42
41
|
else
|
43
42
|
paths = paths.map do |path|
|
44
43
|
path = path.dup
|
45
|
-
path.force_encoding(Encoding::BINARY)
|
44
|
+
path.force_encoding(Encoding::BINARY)
|
46
45
|
if File.symlink?(path)
|
47
46
|
link = path
|
48
47
|
path = File.readlink(link)
|
49
|
-
path.force_encoding(Encoding::BINARY)
|
48
|
+
path.force_encoding(Encoding::BINARY)
|
50
49
|
rv[link] = rv[path] # vivify ListenerStats
|
51
50
|
else
|
52
51
|
rv[path] # vivify ListenerStats
|
@@ -57,7 +56,7 @@ module Raindrops::Linux
|
|
57
56
|
paths = /^\w+: \d+ \d+ (\d+) \d+ (\d+)\s+\d+ (#{paths.join('|')})$/n
|
58
57
|
|
59
58
|
# no point in pread since we can't stat for size on this file
|
60
|
-
File.read(
|
59
|
+
File.read(PROC_NET_UNIX_ARGS[0], encoding: 'binary').scan(paths) do |s|
|
61
60
|
path = s[-1]
|
62
61
|
case s[0]
|
63
62
|
when "00000000" # client sockets
|
@@ -27,9 +27,9 @@ class Raindrops::Middleware::Proxy
|
|
27
27
|
|
28
28
|
# Rack servers use +respond_to?+ to check for the presence of +close+
|
29
29
|
# and +to_path+ methods.
|
30
|
-
def respond_to?(m)
|
30
|
+
def respond_to?(m, include_all = false)
|
31
31
|
m = m.to_sym
|
32
|
-
:close == m || @body.respond_to?(m)
|
32
|
+
:close == m || @body.respond_to?(m, include_all)
|
33
33
|
end
|
34
34
|
|
35
35
|
# Avoid breaking users of non-standard extensions (e.g. #body)
|
data/lib/raindrops/middleware.rb
CHANGED
@@ -62,9 +62,9 @@ require 'raindrops'
|
|
62
62
|
# = Demo Server
|
63
63
|
#
|
64
64
|
# There is a server running this middleware (and Watcher) at
|
65
|
-
# https://raindrops-demo
|
65
|
+
# https://yhbt.net/raindrops-demo/_raindrops
|
66
66
|
#
|
67
|
-
# Also check out the Watcher demo at https://raindrops-demo
|
67
|
+
# Also check out the Watcher demo at https://yhbt.net/raindrops-demo/
|
68
68
|
#
|
69
69
|
# The demo server is only limited to 30 users, so be sure not to abuse it
|
70
70
|
# by using the /tail/ endpoint too much.
|
data/lib/raindrops/watcher.rb
CHANGED
@@ -35,28 +35,28 @@ require "aggregate"
|
|
35
35
|
# Returns a plain text summary + histogram with X-* HTTP headers for
|
36
36
|
# active connections.
|
37
37
|
#
|
38
|
-
# e.g.: curl https://raindrops-demo
|
38
|
+
# e.g.: curl https://yhbt.net/raindrops-demo/active/0.0.0.0%3A80.txt
|
39
39
|
#
|
40
40
|
# === GET /active/$LISTENER.html
|
41
41
|
#
|
42
42
|
# Returns an HTML summary + histogram with X-* HTTP headers for
|
43
43
|
# active connections.
|
44
44
|
#
|
45
|
-
# e.g.: curl https://raindrops-demo
|
45
|
+
# e.g.: curl https://yhbt.net/raindrops-demo/active/0.0.0.0%3A80.html
|
46
46
|
#
|
47
47
|
# === GET /queued/$LISTENER.txt
|
48
48
|
#
|
49
49
|
# Returns a plain text summary + histogram with X-* HTTP headers for
|
50
50
|
# queued connections.
|
51
51
|
#
|
52
|
-
# e.g.: curl https://raindrops-demo
|
52
|
+
# e.g.: curl https://yhbt.net/raindrops-demo/queued/0.0.0.0%3A80.txt
|
53
53
|
#
|
54
54
|
# === GET /queued/$LISTENER.html
|
55
55
|
#
|
56
56
|
# Returns an HTML summary + histogram with X-* HTTP headers for
|
57
57
|
# queued connections.
|
58
58
|
#
|
59
|
-
# e.g.: curl https://raindrops-demo
|
59
|
+
# e.g.: curl https://yhbt.net/raindrops-demo/queued/0.0.0.0%3A80.html
|
60
60
|
#
|
61
61
|
# === POST /reset/$LISTENER
|
62
62
|
#
|
@@ -95,9 +95,9 @@ require "aggregate"
|
|
95
95
|
#
|
96
96
|
# = Demo Server
|
97
97
|
#
|
98
|
-
# There is a server running this app at https://raindrops-demo
|
98
|
+
# There is a server running this app at https://yhbt.net/raindrops-demo/
|
99
99
|
# The Raindrops::Middleware demo is also accessible at
|
100
|
-
# https://raindrops-demo
|
100
|
+
# https://yhbt.net/raindrops-demo/_raindrops
|
101
101
|
#
|
102
102
|
# The demo server is only limited to 30 users, so be sure not to abuse it
|
103
103
|
# by using the /tail/ endpoint too much.
|
@@ -106,7 +106,7 @@ class Raindrops::Watcher
|
|
106
106
|
attr_reader :snapshot
|
107
107
|
include Rack::Utils
|
108
108
|
include Raindrops::Linux
|
109
|
-
DOC_URL = "https://
|
109
|
+
DOC_URL = "https://yhbt.net/raindrops/Raindrops/Watcher.html"
|
110
110
|
Peak = Struct.new(:first, :last)
|
111
111
|
|
112
112
|
def initialize(opts = {})
|
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-public@
|
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
|
@@ -36,6 +36,30 @@ class Raindrops
|
|
36
36
|
def total
|
37
37
|
active + queued
|
38
38
|
end
|
39
|
+
end unless defined? ListenStats
|
40
|
+
|
41
|
+
# call-seq:
|
42
|
+
# Raindrops.new(size, io: nil) -> raindrops object
|
43
|
+
#
|
44
|
+
# Initializes a Raindrops object to hold +size+ counters. +size+ is
|
45
|
+
# only a hint and the actual number of counters the object has is
|
46
|
+
# dependent on the CPU model, number of cores, and page size of
|
47
|
+
# the machine. The actual size of the object will always be equal
|
48
|
+
# or greater than the specified +size+.
|
49
|
+
# If +io+ is provided, then the Raindrops memory will be backed by
|
50
|
+
# the specified file; otherwise, it will allocate anonymous memory.
|
51
|
+
# The IO object must respond to +truncate+, as this is used to set
|
52
|
+
# the size of the file.
|
53
|
+
# If +zero+ is provided, then the memory region is zeroed prior to
|
54
|
+
# returning. This is only meaningful if +io+ is also provided; in
|
55
|
+
# that case it controls whether any existing counter values in +io+
|
56
|
+
# are retained (false) or whether it is entirely zeroed (true).
|
57
|
+
def initialize(size, io: nil, zero: false)
|
58
|
+
# This ruby wrapper exists to handle the keyword-argument handling,
|
59
|
+
# which is otherwise kind of awkward in C. We delegate the keyword
|
60
|
+
# arguments to the _actual_ initialize implementation as positional
|
61
|
+
# args.
|
62
|
+
initialize_cimpl(size, io, zero)
|
39
63
|
end
|
40
64
|
|
41
65
|
autoload :Linux, 'raindrops/linux'
|
data/pkg.mk
CHANGED
@@ -60,7 +60,7 @@ doc:: .document .olddoc.yml $(pkg_extra) $(PLACEHOLDERS)
|
|
60
60
|
-find lib -type f -name '*.rbc' -exec rm -f '{}' ';'
|
61
61
|
-find ext -type f -name '*.rbc' -exec rm -f '{}' ';'
|
62
62
|
$(RM) -r doc
|
63
|
-
$(RDOC) -f
|
63
|
+
$(RDOC) -f dark216
|
64
64
|
$(OLDDOC) merge
|
65
65
|
install -m644 COPYING doc/COPYING
|
66
66
|
install -m644 NEWS doc/NEWS
|
@@ -127,7 +127,8 @@ publish_doc:
|
|
127
127
|
-git set-file-times
|
128
128
|
$(MAKE) doc
|
129
129
|
$(MAKE) doc_gz
|
130
|
-
$(RSYNC) -av doc/ $(RSYNC_DEST)/
|
130
|
+
$(RSYNC) -av doc/ $(RSYNC_DEST)/ \
|
131
|
+
--exclude index.html* --exclude created.rid*
|
131
132
|
git ls-files | xargs touch
|
132
133
|
endif
|
133
134
|
|
data/raindrops.gemspec
CHANGED
@@ -8,13 +8,13 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.version = (ENV["VERSION"] ||= '0.18.0').dup
|
9
9
|
s.authors = ["raindrops hackers"]
|
10
10
|
s.description = File.read('README').split("\n\n")[1]
|
11
|
-
s.email = %q{raindrops-public@
|
11
|
+
s.email = %q{raindrops-public@yhbt.net}
|
12
12
|
s.extensions = %w(ext/raindrops/extconf.rb)
|
13
13
|
s.extra_rdoc_files = IO.readlines('.document').map!(&:chomp!).keep_if do |f|
|
14
14
|
File.exist?(f)
|
15
15
|
end
|
16
16
|
s.files = manifest
|
17
|
-
s.homepage = 'https://
|
17
|
+
s.homepage = 'https://yhbt.net/raindrops/'
|
18
18
|
s.summary = 'real-time stats for preforking Rack servers'
|
19
19
|
s.required_ruby_version = '>= 1.9.3'
|
20
20
|
s.test_files = test_files
|
data/test/ipv6_enabled.rb
CHANGED
@@ -2,8 +2,8 @@ def ipv6_enabled?
|
|
2
2
|
tmp = TCPServer.new(ENV["TEST_HOST6"] || '::1', 0)
|
3
3
|
tmp.close
|
4
4
|
true
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
rescue => e
|
6
|
+
warn "skipping IPv6 tests, host does not seem to be IPv6 enabled:"
|
7
|
+
warn " #{e.class}: #{e}"
|
8
|
+
false
|
9
9
|
end
|
data/test/test_linux.rb
CHANGED
@@ -76,6 +76,7 @@ class TestLinux < Test::Unit::TestCase
|
|
76
76
|
|
77
77
|
assert_equal 0, stats[tmp.path].active
|
78
78
|
assert_equal 0, stats[tmp.path].queued
|
79
|
+
us.close
|
79
80
|
end
|
80
81
|
|
81
82
|
def test_unix_resolves_symlinks
|
@@ -151,8 +152,8 @@ class TestLinux < Test::Unit::TestCase
|
|
151
152
|
assert_equal 1, stats.size
|
152
153
|
assert_equal 0, stats[addr].queued
|
153
154
|
assert_equal 1, stats[addr].active
|
154
|
-
|
155
|
-
|
155
|
+
ensure
|
156
|
+
nlsock.close
|
156
157
|
end
|
157
158
|
|
158
159
|
def test_tcp_multi
|
data/test/test_raindrops.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'test/unit'
|
3
3
|
require 'raindrops'
|
4
|
+
require 'tempfile'
|
4
5
|
|
5
6
|
class TestRaindrops < Test::Unit::TestCase
|
6
7
|
|
@@ -134,7 +135,7 @@ class TestRaindrops < Test::Unit::TestCase
|
|
134
135
|
assert_equal 0, rd[rd.capa - 1]
|
135
136
|
assert_equal 1, rd.incr(rd.capa - 1)
|
136
137
|
assert_raises(ArgumentError) { rd[rd.capa] }
|
137
|
-
|
138
|
+
rescue RangeError
|
138
139
|
end # if RUBY_PLATFORM =~ /linux/
|
139
140
|
|
140
141
|
def test_evaporate
|
@@ -162,4 +163,45 @@ class TestRaindrops < Test::Unit::TestCase
|
|
162
163
|
assert status.success?
|
163
164
|
assert_equal [ 1, 2 ], tmp.to_ary
|
164
165
|
end
|
166
|
+
|
167
|
+
def test_io_backed
|
168
|
+
file = Tempfile.new('test_io_backed')
|
169
|
+
rd = Raindrops.new(4, io: file, zero: true)
|
170
|
+
rd[0] = 123
|
171
|
+
rd[1] = 456
|
172
|
+
|
173
|
+
assert_equal 123, rd[0]
|
174
|
+
assert_equal 456, rd[1]
|
175
|
+
|
176
|
+
rd.evaporate!
|
177
|
+
|
178
|
+
file.rewind
|
179
|
+
data = file.read
|
180
|
+
assert_equal 123, data.unpack('L!')[0]
|
181
|
+
assert_equal 456, data[Raindrops::SIZE..data.size].unpack('L!')[0]
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_io_backed_reuse
|
185
|
+
file = Tempfile.new('test_io_backed')
|
186
|
+
rd = Raindrops.new(4, io: file, zero: true)
|
187
|
+
rd[0] = 123
|
188
|
+
rd[1] = 456
|
189
|
+
rd.evaporate!
|
190
|
+
|
191
|
+
rd = Raindrops.new(4, io: file, zero: false)
|
192
|
+
assert_equal 123, rd[0]
|
193
|
+
assert_equal 456, rd[1]
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_iobacked_noreuse
|
197
|
+
file = Tempfile.new('test_io_backed')
|
198
|
+
rd = Raindrops.new(4, io: file, zero: true)
|
199
|
+
rd[0] = 123
|
200
|
+
rd[1] = 456
|
201
|
+
rd.evaporate!
|
202
|
+
|
203
|
+
rd = Raindrops.new(4, io: file, zero: true)
|
204
|
+
assert_equal 0, rd[0]
|
205
|
+
assert_equal 0, rd[1]
|
206
|
+
end
|
165
207
|
end
|
data/test/test_tcp_info.rb
CHANGED
@@ -60,10 +60,10 @@ class TestTCP_Info < Test::Unit::TestCase
|
|
60
60
|
a = s.accept
|
61
61
|
i = Raindrops::TCP_Info.new(a)
|
62
62
|
assert i.last_data_recv >= delay_ms, "#{i.last_data_recv} < #{delay_ms}"
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
ensure
|
64
|
+
c.close if c
|
65
|
+
a.close if a
|
66
|
+
s.close
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_tcp_server_state_closed
|
data/test/test_watcher.rb
CHANGED
@@ -118,28 +118,28 @@ class TestWatcher < Test::Unit::TestCase
|
|
118
118
|
|
119
119
|
def test_x_current_header
|
120
120
|
env = @req.class.env_for "/active/#@addr.txt"
|
121
|
-
|
121
|
+
_status, headers, _body = @app.call(env)
|
122
122
|
assert_equal "0", headers["X-Current"], headers.inspect
|
123
123
|
|
124
124
|
env = @req.class.env_for "/queued/#@addr.txt"
|
125
|
-
|
125
|
+
_status, headers, _body = @app.call(env)
|
126
126
|
assert_equal "1", headers["X-Current"], headers.inspect
|
127
127
|
|
128
128
|
@ios << @srv.accept
|
129
129
|
sleep 0.1
|
130
130
|
|
131
131
|
env = @req.class.env_for "/queued/#@addr.txt"
|
132
|
-
|
132
|
+
_status, headers, _body = @app.call(env)
|
133
133
|
assert_equal "0", headers["X-Current"], headers.inspect
|
134
134
|
|
135
135
|
env = @req.class.env_for "/active/#@addr.txt"
|
136
|
-
|
136
|
+
_status, headers, _body = @app.call(env)
|
137
137
|
assert_equal "1", headers["X-Current"], headers.inspect
|
138
138
|
end
|
139
139
|
|
140
140
|
def test_peaks
|
141
141
|
env = @req.class.env_for "/active/#@addr.txt"
|
142
|
-
|
142
|
+
_status, headers, _body = @app.call(env.dup)
|
143
143
|
start = headers["X-First-Peak-At"]
|
144
144
|
assert headers["X-First-Peak-At"], headers.inspect
|
145
145
|
assert headers["X-Last-Peak-At"], headers.inspect
|
@@ -148,14 +148,14 @@ class TestWatcher < Test::Unit::TestCase
|
|
148
148
|
before = headers["X-Last-Peak-At"]
|
149
149
|
|
150
150
|
env = @req.class.env_for "/queued/#@addr.txt"
|
151
|
-
|
151
|
+
_status, headers, _body = @app.call(env)
|
152
152
|
assert_nothing_raised { Time.parse(headers["X-First-Peak-At"]) }
|
153
153
|
assert_nothing_raised { Time.parse(headers["X-Last-Peak-At"]) }
|
154
154
|
assert_equal before, headers["X-Last-Peak-At"], "should not change"
|
155
155
|
|
156
156
|
sleep 2
|
157
157
|
env = @req.class.env_for "/active/#@addr.txt"
|
158
|
-
|
158
|
+
_status, headers, _body = @app.call(env.dup)
|
159
159
|
assert_equal before, headers["X-Last-Peak-At"], headers.inspect
|
160
160
|
|
161
161
|
@ios << @srv.accept
|
@@ -167,7 +167,7 @@ class TestWatcher < Test::Unit::TestCase
|
|
167
167
|
end
|
168
168
|
sleep 0.1
|
169
169
|
env = @req.class.env_for "/queued/#@addr.txt"
|
170
|
-
|
170
|
+
_status, headers, _body = @app.call(env.dup)
|
171
171
|
assert headers["X-Last-Peak-At"], headers.inspect
|
172
172
|
assert_nothing_raised { Time.parse(headers["X-Last-Peak-At"]) }
|
173
173
|
assert before != headers["X-Last-Peak-At"]
|
@@ -177,7 +177,7 @@ class TestWatcher < Test::Unit::TestCase
|
|
177
177
|
sleep 2
|
178
178
|
|
179
179
|
env = @req.class.env_for "/queued/#@addr.txt"
|
180
|
-
|
180
|
+
_status, headers, _body = @app.call(env)
|
181
181
|
assert_equal "0", headers["X-Current"]
|
182
182
|
assert_nothing_raised { Time.parse(headers["X-Last-Peak-At"]) }
|
183
183
|
assert_equal queued_before, headers["X-Last-Peak-At"], "should not change"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: raindrops
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- raindrops hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-12-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aggregate
|
@@ -78,7 +78,7 @@ description: |-
|
|
78
78
|
should support any Rack HTTP server on platforms supporting POSIX shared
|
79
79
|
memory. It may also be used as a generic scoreboard for sharing atomic
|
80
80
|
counters across multiple processes.
|
81
|
-
email: raindrops-public@
|
81
|
+
email: raindrops-public@yhbt.net
|
82
82
|
executables: []
|
83
83
|
extensions:
|
84
84
|
- ext/raindrops/extconf.rb
|
@@ -149,7 +149,7 @@ files:
|
|
149
149
|
- test/test_struct.rb
|
150
150
|
- test/test_tcp_info.rb
|
151
151
|
- test/test_watcher.rb
|
152
|
-
homepage: https://
|
152
|
+
homepage: https://yhbt.net/raindrops/
|
153
153
|
licenses:
|
154
154
|
- LGPL-2.1+
|
155
155
|
metadata: {}
|
@@ -168,8 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
168
|
- !ruby/object:Gem::Version
|
169
169
|
version: '0'
|
170
170
|
requirements: []
|
171
|
-
|
172
|
-
rubygems_version: 2.6.10
|
171
|
+
rubygems_version: 3.0.2
|
173
172
|
signing_key:
|
174
173
|
specification_version: 4
|
175
174
|
summary: real-time stats for preforking Rack servers
|