raindrops 0.13.0 → 0.20.0

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.document +1 -2
  3. data/.gitattributes +4 -0
  4. data/.gitignore +1 -1
  5. data/.manifest +7 -5
  6. data/.olddoc.yml +16 -0
  7. data/GIT-VERSION-FILE +1 -1
  8. data/GIT-VERSION-GEN +1 -1
  9. data/GNUmakefile +1 -2
  10. data/LATEST +6 -11
  11. data/LICENSE +3 -3
  12. data/NEWS +158 -0
  13. data/README +33 -40
  14. data/TODO +2 -0
  15. data/archive/.gitignore +3 -0
  16. data/archive/slrnpull.conf +4 -0
  17. data/examples/linux-listener-stats.rb +1 -2
  18. data/examples/watcher_demo.ru +1 -1
  19. data/examples/yahns.conf.rb +30 -0
  20. data/examples/zbatery.conf.rb +4 -1
  21. data/ext/raindrops/extconf.rb +107 -2
  22. data/ext/raindrops/linux_inet_diag.c +94 -101
  23. data/ext/raindrops/raindrops.c +75 -21
  24. data/ext/raindrops/tcp_info.c +245 -0
  25. data/lib/raindrops/aggregate/last_data_recv.rb +1 -5
  26. data/lib/raindrops/aggregate/pmq.rb +23 -17
  27. data/lib/raindrops/aggregate.rb +1 -1
  28. data/lib/raindrops/linux.rb +5 -6
  29. data/lib/raindrops/middleware/proxy.rb +2 -2
  30. data/lib/raindrops/middleware.rb +4 -6
  31. data/lib/raindrops/watcher.rb +13 -13
  32. data/lib/raindrops.rb +25 -1
  33. data/pkg.mk +26 -50
  34. data/raindrops.gemspec +14 -21
  35. data/test/ipv6_enabled.rb +4 -4
  36. data/test/test_aggregate_pmq.rb +1 -1
  37. data/test/test_inet_diag_socket.rb +1 -1
  38. data/test/test_last_data_recv_unicorn.rb +1 -1
  39. data/test/test_linux.rb +10 -2
  40. data/test/test_linux_all_tcp_listen_stats_leak.rb +2 -2
  41. data/test/test_linux_ipv6.rb +8 -0
  42. data/test/test_raindrops.rb +43 -1
  43. data/test/{test_linux_tcp_info.rb → test_tcp_info.rb} +34 -14
  44. data/test/test_watcher.rb +15 -10
  45. metadata +59 -171
  46. data/.wrongdoc.yml +0 -6
  47. data/ChangeLog +0 -1920
  48. data/Rakefile +0 -28
  49. data/ext/raindrops/linux_tcp_info.c +0 -173
@@ -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 */
@@ -13,10 +13,6 @@ require "socket"
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 @@ module Raindrops::Aggregate::LastDataRecv
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 @@ require "tempfile"
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 @@ require "thread"
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. Using this class requires the following additional RubyGems
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 @@ class Raindrops::Aggregate::PMQ
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 @@ 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
@@ -151,7 +151,10 @@ class Raindrops::Aggregate::PMQ
151
151
  @cached_aggregate ||= begin
152
152
  flush
153
153
  Marshal.load(synchronize(@rd, RDLOCK) do |rd|
154
- IO.pread rd.fileno, rd.stat.size, 0
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 @@ class Raindrops::Aggregate::PMQ
163
166
  dump = Marshal.dump @aggregate
164
167
  synchronize(@wr, WRLOCK) do |wr|
165
168
  wr.truncate 0
166
- IO.pwrite wr.fileno, dump, 0
169
+ wr.rewind
170
+ wr.write(dump)
167
171
  end
168
172
  end
169
173
 
@@ -171,24 +175,26 @@ class Raindrops::Aggregate::PMQ
171
175
  # worker thread or process
172
176
  def stop_master_loop
173
177
  sleep 0.1 until mq_send(false)
174
- rescue Errno::EINTR
175
- retry
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
- rescue Errno::EINTR
181
- retry
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
@@ -1,6 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
2
  #
3
- # raindrops may use the {aggregate}[http://github.com/josephruscio/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"
@@ -8,15 +8,13 @@
8
8
  # Instead of snapshotting, Raindrops::Aggregate::LastDataRecv may be used
9
9
  # to aggregate statistics from +all+ accepted sockets as they arrive
10
10
  # based on the +last_data_recv+ field in Raindrops::TCP_Info
11
- require 'pathname'
12
11
 
13
12
  module Raindrops::Linux
14
13
 
15
14
  # The standard proc path for active UNIX domain sockets, feel free to call
16
15
  # String#replace on this if your /proc is mounted in a non-standard location
17
16
  # for whatever reason
18
- PROC_NET_UNIX_ARGS = %w(/proc/net/unix)
19
- defined?(::Encoding) and PROC_NET_UNIX_ARGS.push({ :encoding => "binary" })
17
+ PROC_NET_UNIX_ARGS = [ '/proc/net/unix', { encoding: "binary" }]
20
18
 
21
19
  # Get ListenStats from an array of +paths+
22
20
  #
@@ -43,10 +41,11 @@ module Raindrops::Linux
43
41
  else
44
42
  paths = paths.map do |path|
45
43
  path = path.dup
46
- path.force_encoding(Encoding::BINARY) if defined?(Encoding)
44
+ path.force_encoding(Encoding::BINARY)
47
45
  if File.symlink?(path)
48
46
  link = path
49
- path = Pathname.new(link).realpath.to_s
47
+ path = File.readlink(link)
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
- # http://raindrops-demo.bogomips.org/_raindrops
65
+ # https://yhbt.net/raindrops-demo/_raindrops
66
66
  #
67
- # Also check out the Watcher demo at http://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.
@@ -77,11 +77,9 @@ class Raindrops::Middleware
77
77
  # and both counters are updated atomically.
78
78
  #
79
79
  # This is supported on all operating systems supported by Raindrops
80
- class Stats < Raindrops::Struct.new(:calling, :writing)
81
- end
80
+ Stats = Raindrops::Struct.new(:calling, :writing)
82
81
 
83
82
  # :stopdoc:
84
- PATH_INFO = "PATH_INFO"
85
83
  require "raindrops/middleware/proxy"
86
84
  # :startdoc:
87
85
 
@@ -111,7 +109,7 @@ class Raindrops::Middleware
111
109
 
112
110
  # standard Rack endpoint
113
111
  def call(env) # :nodoc:
114
- env[PATH_INFO] == @path and return stats_response
112
+ env['PATH_INFO'] == @path and return stats_response
115
113
  begin
116
114
  @stats.incr_calling
117
115
 
@@ -8,7 +8,7 @@ require "aggregate"
8
8
  # Raindrops::Watcher is a stand-alone Rack application for watching
9
9
  # any number of TCP and UNIX listeners (all of them by default).
10
10
  #
11
- # It depends on the {Aggregate RubyGem}[http://rubygems.org/gems/aggregate]
11
+ # It depends on the {Aggregate RubyGem}[https://rubygems.org/gems/aggregate]
12
12
  #
13
13
  # In your Rack config.ru:
14
14
  #
@@ -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 http://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 http://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 http://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 http://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 http://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
- # http://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 = "http://raindrops.bogomips.org/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 = {})
@@ -244,10 +244,10 @@ class Raindrops::Watcher
244
244
  def histogram_txt(agg)
245
245
  updated_at, reset_at, agg, current, peak = *agg
246
246
  headers = agg_to_hash(reset_at, agg, current, peak)
247
- body = agg.to_s
247
+ body = agg.to_s # 7-bit ASCII-clean
248
248
  headers["Content-Type"] = "text/plain"
249
249
  headers["Expires"] = (updated_at + @delay).httpdate
250
- headers["Content-Length"] = bytesize(body).to_s
250
+ headers["Content-Length"] = body.size.to_s
251
251
  [ 200, headers, [ body ] ]
252
252
  end
253
253
 
@@ -265,7 +265,7 @@ class Raindrops::Watcher
265
265
  "</body>"
266
266
  headers["Content-Type"] = "text/html"
267
267
  headers["Expires"] = (updated_at + @delay).httpdate
268
- headers["Content-Length"] = bytesize(body).to_s
268
+ headers["Content-Length"] = body.size.to_s
269
269
  [ 200, headers, [ body ] ]
270
270
  end
271
271
 
@@ -364,7 +364,7 @@ class Raindrops::Watcher
364
364
  "for more information and options." \
365
365
  "</p>" \
366
366
  "</body></html>"
367
- headers["Content-Length"] = bytesize(body).to_s
367
+ headers["Content-Length"] = body.size.to_s
368
368
  [ 200, headers, [ body ] ]
369
369
  end
370
370
 
@@ -382,7 +382,7 @@ class Raindrops::Watcher
382
382
  q = Rack::Utils.parse_query env["QUERY_STRING"]
383
383
  @active_min = q["active_min"].to_i
384
384
  @queued_min = q["queued_min"].to_i
385
- len = Rack::Utils.bytesize(addr)
385
+ len = addr.size
386
386
  len = 35 if len > 35
387
387
  @fmt = "%20s % #{len}s % 10u % 10u\n"
388
388
  case env["HTTP_VERSION"]
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@librelist.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'