drbdump 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b3f2cd54ef03808d4d62ec58bbf6988a5a40657e
4
+ data.tar.gz: c83c65fb484a4aa329aa943b08c6b63f95061d68
5
+ SHA512:
6
+ metadata.gz: f8a8f622a06fdadd9495f13136bfc9c8acbb8a1e43d2a427c0cba184830324919f235916ecfb6249cb8637d7207ad7ef5c27fb29d6e19e7552a0cc39d2674af7
7
+ data.tar.gz: 8ff6002c16d643c7e88300ab91546595a247dc0e5b46a666c8f42bf08e2d89b6ad69f6991db645b4d8a0acb2e41674aba752065ac0b04fde9460ad83547d957c
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.testlib = 'minitest/autorun'
7
+ end
8
+
File without changes
@@ -0,0 +1,4 @@
1
+ === 1.0 / 2013-05-31
2
+
3
+ * Birthday!
4
+
@@ -0,0 +1,30 @@
1
+ .autotest
2
+ History.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ bin/drbdump
7
+ example/ping.rb
8
+ example/service_primes.rb
9
+ example/tuplespace_primes.rb
10
+ lib/drbdump.rb
11
+ lib/drbdump/loader.rb
12
+ lib/drbdump/message.rb
13
+ lib/drbdump/message_result.rb
14
+ lib/drbdump/message_send.rb
15
+ lib/drbdump/statistic.rb
16
+ lib/drbdump/statistics.rb
17
+ lib/drbdump/test_case.rb
18
+ test/arg.dump
19
+ test/drb_fin.dump
20
+ test/http.dump
21
+ test/ping.dump
22
+ test/ring.dump
23
+ test/test_drbdump.rb
24
+ test/test_drbdump_loader.rb
25
+ test/test_drbdump_message.rb
26
+ test/test_drbdump_message_result.rb
27
+ test/test_drbdump_message_send.rb
28
+ test/test_drbdump_statistic.rb
29
+ test/test_drbdump_statistics.rb
30
+ test/too_large_packet.pcap
@@ -0,0 +1,71 @@
1
+ = drbdump
2
+
3
+ home :: https://github.com/drbrain/drbdump
4
+ rdoc :: http://docs.seattlerb.org/drbdump
5
+ bugs :: https://github.com/drbrain/drbdump/issues
6
+
7
+ == Description
8
+
9
+ drbdump is a tcpdump-like tool for the dRuby protocol. It allows you to
10
+ inspect the message and analyze the messages sent between your DRb-using
11
+ processes.
12
+
13
+ == Features
14
+
15
+ * Displays DRb message sends and results
16
+ * Displays Rinda service discovery announcements
17
+ * Records DRb message statistics including allocations and latency
18
+
19
+ == Problems
20
+
21
+ * Does not handle out-of-order or resent TCP packets
22
+ * Does not handle mDNS
23
+ * Does not support filtering
24
+ * TCP only
25
+
26
+ == Usage
27
+
28
+ To show DRb messages:
29
+
30
+ sudo drbdump
31
+
32
+ See the DRbDump class documentation for a full description of drbdump
33
+
34
+ == Installation
35
+
36
+ sudo gem install drbdump
37
+
38
+ == Developers
39
+
40
+ After checking out the source, run:
41
+
42
+ $ rake newb
43
+
44
+ This task will install any missing dependencies, run the tests/specs,
45
+ and generate the RDoc.
46
+
47
+ == License
48
+
49
+ (The MIT License)
50
+
51
+ Copyright (c) Eric Hodel
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
71
+
@@ -0,0 +1,30 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :git
7
+ Hoe.plugin :minitest
8
+ Hoe.plugin :travis
9
+
10
+ namespace :travis do
11
+ task :install_libpcap do
12
+ sh 'sudo apt-get install libpcap-dev'
13
+ end
14
+
15
+ task before: %w[install_libpcap]
16
+ end
17
+
18
+ Hoe.spec 'drbdump' do
19
+ developer 'Eric Hodel', 'drbrain@segment7.net'
20
+
21
+ rdoc_locations << 'docs.seattlerb.org:/data/www/docs.seattlerb.org/drbdump/'
22
+
23
+ self.readme_file = 'README.rdoc'
24
+ self.licenses << 'MIT'
25
+
26
+ self.extra_deps << ['capp', '~> 1.0']
27
+ self.extra_deps << ['marshal-structure', '~> 2.0']
28
+ end
29
+
30
+ # vim: syntax=ruby
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'drbdump'
4
+
5
+ DRbDump.run ARGV
6
+
@@ -0,0 +1,241 @@
1
+ require 'drb'
2
+ require 'drbdump'
3
+ require 'optparse'
4
+
5
+ class Ping
6
+
7
+ class Responder
8
+ def ping i, data
9
+ return i, data
10
+ end
11
+ end
12
+
13
+ def self.process_args argv
14
+ options = {
15
+ client: nil,
16
+ count: Float::INFINITY,
17
+ flood: false,
18
+ interval: 1,
19
+ reconnect: false,
20
+ server: false,
21
+ size: 0,
22
+ }
23
+
24
+ interval_set = false
25
+
26
+ op = OptionParser.new do |opt|
27
+ opt.banner = <<-BANNER
28
+ Usage: ping.rb [options] [druby://...]
29
+
30
+ With no arguments, spawns a child process and sends DRb messages to it
31
+
32
+ To ping across multiple machines start a server with:
33
+
34
+ ping.rb --server
35
+
36
+ And submit the given URI to a client:
37
+
38
+ ping.rb druby://...
39
+ BANNER
40
+
41
+ opt.separator nil
42
+ opt.separator 'Options:'
43
+
44
+ opt.on('-c', '--count COUNT', Integer,
45
+ 'Number of packets to send') do |count|
46
+ options[:count] = count
47
+ end
48
+
49
+ opt.on('-f', '--flood',
50
+ 'Send packets as fast as possible',
51
+ 'Prints one . per 1000 messages') do
52
+ options[:flood] = true
53
+ end
54
+
55
+ opt.on('-i', '--interval SECONDS', Float,
56
+ 'Time between non-flood packets') do |interval|
57
+ options[:interval] = interval
58
+ interval_set = true
59
+ end
60
+
61
+ opt.on('-s', '--packet-size SIZE', Integer,
62
+ 'Size of extra data to send') do |size|
63
+ options[:size] = size
64
+ end
65
+
66
+ opt.on( '--reconnect',
67
+ 'Reconnect for each ping') do
68
+ options[:reconnect] = true
69
+ end
70
+
71
+ opt.on( '--server',
72
+ 'Run only as a server') do |value|
73
+ options[:server] = true
74
+ end
75
+ end
76
+
77
+ op.parse! argv
78
+
79
+ raise OptionParser::ParseError, '--flood with --interval is nonsense' if
80
+ options[:flood] and interval_set
81
+
82
+ raise OptionParser::ParseError, '--server with --flood is nonsense' if
83
+ options[:server] and options[:flood]
84
+
85
+ raise OptionParser::ParseError, '--server with --count is nonsense' if
86
+ options[:server] and options[:count]
87
+
88
+ options[:client] = argv.shift if /\Adruby:/ =~ argv.first
89
+
90
+ raise OptionParser::ParseError, '--server with client URI is nonsense' if
91
+ options[:server] and options[:client]
92
+
93
+ options
94
+ rescue OptionParser::ParseError => e
95
+ $stderr.puts op
96
+ $stderr.puts
97
+ $stderr.puts e.message
98
+
99
+ abort
100
+ end
101
+
102
+ def self.run argv = ARGV
103
+ options = process_args argv
104
+
105
+ ping = new options
106
+
107
+ ping.run
108
+ end
109
+
110
+ def initialize options
111
+ @count = options[:count]
112
+ @client = options[:client]
113
+ @flood = options[:flood]
114
+ @interval = options[:interval]
115
+ @reconnect = options[:reconnect]
116
+ @remote = nil
117
+ @server = options[:server]
118
+ @size = options[:size]
119
+ @uri = nil
120
+
121
+ @data = ('a'..'z').cycle.first(@size).join
122
+ end
123
+
124
+ def delay_ping
125
+ statistic = DRbDump::Statistic.new
126
+ seq = 0
127
+
128
+ until (seq += 1) > @count do
129
+ send_message seq, statistic
130
+ end
131
+ ensure
132
+ puts
133
+ puts delay_statistics statistic
134
+ end
135
+
136
+ def delay_statistics statistic
137
+ '%d messages, min/avg/max/stddev = %0.3f/%0.3f/%0.3f/%0.3f ms' % [
138
+ statistic.count, statistic.min, statistic.mean, statistic.max,
139
+ statistic.standard_deviation
140
+ ]
141
+ end
142
+
143
+ def flood_ping
144
+ start = Time.now
145
+ seq = 0
146
+
147
+ until (seq += 1) > @count do
148
+ begin
149
+ @remote.ping seq, @data
150
+ rescue DRb::DRbConnError
151
+ end
152
+
153
+ reconnect
154
+
155
+ print '.' if seq % 1000 == 0
156
+ end
157
+ ensure
158
+ elapsed = Time.now - start
159
+ puts
160
+ puts flood_statistics(elapsed, seq - 1)
161
+ end
162
+
163
+ def flood_statistics elapsed, messages
164
+ '%d messages in %0.3f seconds, %d messages/sec' % [
165
+ messages, elapsed, messages / elapsed
166
+ ]
167
+ end
168
+
169
+ def loopback
170
+ uri = DRb.uri
171
+
172
+ pid = fork do
173
+ DRb.stop_service
174
+
175
+ DRb.start_service
176
+
177
+ ping uri
178
+ end
179
+
180
+ trap 'INT' do Process.kill 'INT', pid end
181
+ trap 'TERM' do Process.kill 'TERM', pid end
182
+
183
+ Process.wait pid
184
+ end
185
+
186
+ def ping uri
187
+ @uri = uri
188
+ @remote = DRb::DRbObject.new_with_uri @uri
189
+
190
+ if @flood then
191
+ flood_ping
192
+ else
193
+ delay_ping
194
+ end
195
+ end
196
+
197
+ def reconnect
198
+ return unless @reconnect
199
+
200
+ DRb::DRbConn.open @uri do [false, false] end
201
+ end
202
+
203
+ def run
204
+ DRb.start_service nil, Responder.new
205
+
206
+ if @server then
207
+ puts DRb.uri
208
+
209
+ DRb.thread.join
210
+ elsif @client then
211
+ ping @client
212
+ else
213
+ loopback
214
+ end
215
+ end
216
+
217
+ def send_message seq, statistic
218
+ message = 'success'
219
+ start = Time.now
220
+
221
+ begin
222
+ @remote.ping seq, @data
223
+ rescue DRb::DRbConnError => e
224
+ message = e
225
+ end
226
+
227
+ elapsed = (Time.now - start) * 1000
228
+
229
+ statistic.add elapsed
230
+
231
+ puts '%s %s: seq=%d time=%0.3f ms' % [@uri, message, seq, elapsed]
232
+
233
+ reconnect
234
+
235
+ sleep @interval
236
+ end
237
+
238
+ end
239
+
240
+ Ping.run ARGV if $0 == __FILE__
241
+
@@ -0,0 +1,212 @@
1
+ require 'drb'
2
+ require 'observer'
3
+ require 'thread'
4
+
5
+ ##
6
+ # Generates primes using multiple independent services. This prime number
7
+ # generator is purposefully ridiculous in its separation of services.
8
+ #
9
+ # == Implementation Notes
10
+ #
11
+ # ServicePrimes contains the following services:
12
+ #
13
+ # :primes::
14
+ # NumberStore holding prime numbers and Observable for notification of newly
15
+ # added prime numbers.
16
+ # :candidates::
17
+ # Enumerator from 3 to infinity for candidates.
18
+ # :discover::
19
+ # Consumes an item from the :candidates service and adds the number to the
20
+ # :primes service if it is found to be prime.
21
+ # :show_primes::
22
+ # Observer for the :primes NumberStore that prints added primes to standard
23
+ # output
24
+ #
25
+ # ServicePrimes can be collapsed back to a single process by removing
26
+ # fork_child and assigning each service to the instance variable used by each
27
+ # service.
28
+ #
29
+ # == Analyzing with drbdump
30
+ #
31
+ # Setup and finding the first prime (3) occurs within the first 15 messages.
32
+ #
33
+ # Comparing short message capture (100 messages) at the beginning of prime
34
+ # generation followed by later (around 70001) shows test_prime doing more work
35
+ # as the number of +call+ messages becomes a larger fraction of the messages
36
+ # sent.
37
+ #
38
+ # Removing DrbUndumped from NumberStore and NumberShower gives an interesting
39
+ # failure where the Observer fails to register.
40
+
41
+ class ServicePrimes
42
+
43
+ ##
44
+ # An observer for NumberStore that prints numbers as they are added.
45
+
46
+ class NumberShower
47
+ include DRb::DRbUndumped
48
+
49
+ ##
50
+ # Prints the number to standard output
51
+
52
+ def update number
53
+ puts number
54
+ end
55
+ end
56
+
57
+ ##
58
+ # Stores primes and allows access to generated primes. The NumberStore is
59
+ # pre-primed with the first prime number (2). The NumberStore is Observable
60
+ # and will notify observers when a new prime is added.
61
+
62
+ class NumberStore
63
+ include DRb::DRbUndumped
64
+ include Enumerable
65
+ include Observable
66
+
67
+ def initialize # :nodoc:
68
+ @primes = [2]
69
+ end
70
+
71
+ ##
72
+ # Adds a number +value+ and notifies observers
73
+
74
+ def add value
75
+ changed
76
+ @primes << value
77
+ notify_observers value
78
+ end
79
+
80
+ ##
81
+ # Iterates through stored primes
82
+
83
+ def each
84
+ @primes.each do |prime|
85
+ yield prime
86
+ end
87
+ end
88
+ end
89
+
90
+ def initialize # :nodoc:
91
+ @services = {}
92
+
93
+ DRb.start_service nil, @services
94
+
95
+ @uri = DRb.uri
96
+ end
97
+
98
+ ##
99
+ # Creates a candidate numbers service which is enumerator of integers from 3
100
+ # to infinity.
101
+
102
+ def candidates
103
+ fork_child :candidates do
104
+ @services[:candidates] = 3.upto Float::INFINITY
105
+
106
+ DRb.thread.join
107
+ end
108
+ end
109
+
110
+ ##
111
+ # Creates a prime number discovery service which consumes a candidate number
112
+ # and uses +test_prime+ to determine if the candidate number is prime. If
113
+ # the candidate is prime it is added to the prime number list.
114
+
115
+ def discover
116
+ fork_child :discover do
117
+ candidates = @services[:candidates]
118
+ @primes = @services[:primes]
119
+
120
+ candidates.each do |candidate|
121
+ prime = test_prime candidate
122
+
123
+ @primes.add candidate if prime
124
+ end
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Forks a worker child named +service+ and waits for its registration before
130
+ # returning.
131
+
132
+ def fork_child service
133
+ Thread.start do
134
+ pid = fork do
135
+ DRb.stop_service
136
+
137
+ DRb.start_service
138
+
139
+ @services = DRb::DRbObject.new_with_uri @uri
140
+
141
+ yield
142
+ end
143
+
144
+ Process.wait pid
145
+ end
146
+
147
+ Thread.pass until @services[service]
148
+ end
149
+
150
+ ##
151
+ # Creates a prime number storage service named primes.
152
+
153
+ def primes
154
+ fork_child :primes do
155
+ @services[:primes] = NumberStore.new
156
+
157
+ DRb.thread.join
158
+ end
159
+ end
160
+
161
+ ##
162
+ # Starts the prime number generator
163
+
164
+ def run
165
+ candidates
166
+
167
+ primes
168
+
169
+ show_primes
170
+
171
+ discover
172
+
173
+ DRb.thread.join
174
+ end
175
+
176
+ ##
177
+ # Creates a prime number display service that observes the addition of new
178
+ # prime numbers to the primes service.
179
+
180
+ def show_primes
181
+ fork_child :show_primes do
182
+ prime_shower = NumberShower.new
183
+
184
+ @services[:primes].add_observer prime_shower
185
+
186
+ @services[:show_primes] = prime_shower
187
+
188
+ DRb.thread.join
189
+ end
190
+ end
191
+
192
+ ##
193
+ # Determines if +candidate+ is a prime number by dividing it by all primes
194
+ # below the square root of the +candidate+.
195
+
196
+ def test_prime candidate
197
+ max = Math.sqrt(candidate).ceil
198
+
199
+ is_prime = @primes.each do |prime|
200
+ break true if prime > max
201
+
202
+ _, remainder = candidate.divmod prime
203
+
204
+ break false if remainder.zero?
205
+ end
206
+
207
+ is_prime
208
+ end
209
+
210
+ end
211
+
212
+ ServicePrimes.new.run if $0 == __FILE__