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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b8dbbea0d1ec6311fe4433caa527f1ca5483f63b
4
- data.tar.gz: e89d864999d618bc1c93df83569d7326924dfa74
2
+ SHA256:
3
+ metadata.gz: 6f78e29ec57e3f3710146a423cf60915d23a5f4366d70dcabbbef74fb69f71f3
4
+ data.tar.gz: 8a369d49c33a67af3b6acccaf64b04ed192cba9d163c8d48944cfac887511885
5
5
  SHA512:
6
- metadata.gz: fe837f974b975b0582c9a86d041acd823dc78b83aaffc2d35bb721d6da2544a6771fbf53d3ea8a2db6240b0ef05d463bd9572e85375f3600227f08fd44fb6cdd
7
- data.tar.gz: 9b380c94a516fbb9df57773f19722314a5c294810ed7f0e4b3027e7a3581c6aefcb0c6f5d5326c4400024e55cf856350e396e37934c781042098297239baafb4
6
+ metadata.gz: b9e5de8e7a7a84038bbe19a954d3d559ebec3ed4c7f68db2e2ada6373b045f4fbcd784c5d5b91005cad1d87f1db93f9dc31c9f7fc59ae56a7f73b98d9a96bf2e
7
+ data.tar.gz: 9913e9205b2527b9f5bd1bae58b0c2c8962505e87280c06257f603fb722978d6656c99cfa0a297ccd0734a7d6110b0a6ecd5155fec9870ec40a31044a00def4d
data/.olddoc.yml CHANGED
@@ -1,14 +1,16 @@
1
1
  ---
2
- cgit_url: https://bogomips.org/raindrops.git
3
- git_url: git://bogomips.org/raindrops.git
4
- rdoc_url: https://bogomips.org/raindrops/
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://bogomips.org/raindrops-public/
8
- - http://ou63pmih66umazou.onion/raindrops-public
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
- - nntp://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
11
- - nntp://ou63pmih66umazou.onion/inbox.comp.lang.ruby.raindrops
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 git://bogomips.org/raindrops.git
14
- - git clone https://bogomips.org/raindrops.git
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.18.0
1
+ GIT_VERSION = 0.20.0
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.18.0
4
+ DEF_VER=v0.20.0
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -1,4 +1,4 @@
1
1
  all::
2
- RSYNC_DEST := bogomips.org:/srv/bogomips/raindrops
2
+ RSYNC_DEST := yhbt.net:/srv/yhbt/raindrops
3
3
  rfpackage := raindrops
4
4
  include pkg.mk
data/LATEST CHANGED
@@ -1,42 +1,10 @@
1
- === raindrops 0.18.0 / 2017-03-23 02:44 UTC
1
+ === raindrops 0.20.0 / 2021-12-06 23:41 UTC
2
2
 
3
- The most notable feature of this release is the addition of
4
- FreeBSD and OpenBSD TCP_INFO support. This includes the
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
- https://bogomips.org/raindrops/Raindrops.html#TCP
6
+ https://yhbt.net/raindrops-public/20211125065618.3432-1-ktsanaktsidis@zendesk.com/T/
9
7
 
10
- Thanks to Jeremy Evans and Simon Eskildsen on the
11
- unicorn-public@bogomips.org mailing list for inspiring
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 publically archived mailing list
62
- (mailto:raindrops-public@bogomips.org) if
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
- git://bogomips.org/raindrops.git
70
- git://repo.or.cz/raindrops.git (mirror)
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
- You may browse the code from the web and download the latest snapshot
73
- tarballs here:
72
+ Snapshots and tarballs are available.
74
73
 
75
- * https://bogomips.org/raindrops.git
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 publically archived mailing list:
93
- mailto:raindrops-public@bogomips.org
88
+ requests) go to the publicly archived mailbox:
89
+ mailto:raindrops-public@yhbt.net
94
90
 
95
- Mailing list archives are available over HTTPS and NNTP:
91
+ Mail archives are available over HTTP(S), IMAP(S) and NNTP(S):
96
92
 
97
- * https://bogomips.org/raindrops-public/
98
- * nntp://news.public-inbox.org/inbox.comp.lang.ruby.raindrops
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') { all = true }
27
+ opts.on('-a', '--all') { } # noop
29
28
  opts.parse! ARGV
30
29
  end
31
30
 
@@ -1,5 +1,5 @@
1
1
  # This is a snippet of the config that powers
2
- # https://raindrops-demo.bogomips.org/
2
+ # https://yhbt.net/raindrops-demo/
3
3
  # This may be used with the packaged zbatery.conf.rb
4
4
  #
5
5
  # zbatery -c zbatery.conf.ru watcher_demo.ru -E none
@@ -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
- prev_cflags = $CFLAGS
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
- #ifdef HAVE_RUBY_ST_H
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
- # define rb_thread_io_blocking_region(fn,data,fd) \
42
- rb_thread_blocking_region((fn),(data),RUBY_UBF_IO,0)
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@bogomips.org\n");
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(rb_thread_io_blocking_region(diag, args, args->fd));
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(rb_thread_io_blocking_region(diag, &args, args.fd));
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);
@@ -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
- { NULL, rd_free, rd_memsize, /* reserved */ },
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
- * call-seq:
91
- * Raindrops.new(size) -> raindrops object
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 init(VALUE self, VALUE size)
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->drops = mmap(NULL, tmp,
118
- PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
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
- init(dest, SIZET2NUM(src->size));
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
- rb_define_method(cRaindrops, "initialize", init, 1);
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();
@@ -1,5 +1,4 @@
1
1
  #include <ruby.h>
2
- #include "extconf.h"
3
2
  #include <sys/socket.h>
4
3
  #include <netinet/in.h>
5
4
  #if defined(HAVE_LINUX_TCP_H)
@@ -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
- ensure
146
- flush_master
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
- rescue Errno::EINTR
179
- retry
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
- rescue Errno::EINTR
185
- retry
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
@@ -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 = %w(/proc/net/unix)
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) if defined?(Encoding)
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) if defined?(Encoding)
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(*PROC_NET_UNIX_ARGS).scan(paths) do |s|
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)
@@ -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.bogomips.org/_raindrops
65
+ # https://yhbt.net/raindrops-demo/_raindrops
66
66
  #
67
- # Also check out the Watcher demo at https://raindrops-demo.bogomips.org/
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.
@@ -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.bogomips.org/active/0.0.0.0%3A80.txt
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.bogomips.org/active/0.0.0.0%3A80.html
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.bogomips.org/queued/0.0.0.0%3A80.txt
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.bogomips.org/queued/0.0.0.0%3A80.html
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.bogomips.org/
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.bogomips.org/_raindrops
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://bogomips.org/raindrops/Raindrops/Watcher.html"
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@bogomips.org
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 oldweb
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@bogomips.org}
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://bogomips.org/raindrops/'
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
- rescue => e
6
- warn "skipping IPv6 tests, host does not seem to be IPv6 enabled:"
7
- warn " #{e.class}: #{e}"
8
- false
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
- ensure
155
- nlsock.close
155
+ ensure
156
+ nlsock.close
156
157
  end
157
158
 
158
159
  def test_tcp_multi
@@ -37,7 +37,7 @@ class TestLinuxAllTcpListenStatsLeak < Test::Unit::TestCase
37
37
  end
38
38
  cur_kb = rss_kb
39
39
  p [ :cur_kb, cur_kb ]
40
- ensure
41
- s.close
40
+ ensure
41
+ s.close
42
42
  end
43
43
  end if ENV["STRESS"].to_i != 0
@@ -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
- rescue RangeError
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
@@ -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
- ensure
64
- c.close if c
65
- a.close if a
66
- s.close
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
- status, headers, body = @app.call(env)
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
- status, headers, body = @app.call(env)
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
- status, headers, body = @app.call(env)
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
- status, headers, body = @app.call(env)
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
- status, headers, body = @app.call(env.dup)
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
- status, headers, body = @app.call(env)
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
- status, headers, body = @app.call(env.dup)
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
- status, headers, body = @app.call(env.dup)
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
- status, headers, body = @app.call(env)
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.18.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: 2017-03-23 00:00:00.000000000 Z
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@bogomips.org
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://bogomips.org/raindrops/
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
- rubyforge_project:
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