drbdump 1.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.autotest +8 -0
- data/.gemtest +0 -0
- data/History.rdoc +4 -0
- data/Manifest.txt +30 -0
- data/README.rdoc +71 -0
- data/Rakefile +30 -0
- data/bin/drbdump +6 -0
- data/example/ping.rb +241 -0
- data/example/service_primes.rb +212 -0
- data/example/tuplespace_primes.rb +196 -0
- data/lib/drbdump.rb +714 -0
- data/lib/drbdump/loader.rb +75 -0
- data/lib/drbdump/message.rb +72 -0
- data/lib/drbdump/message_result.rb +84 -0
- data/lib/drbdump/message_send.rb +146 -0
- data/lib/drbdump/statistic.rb +90 -0
- data/lib/drbdump/statistics.rb +318 -0
- data/lib/drbdump/test_case.rb +91 -0
- data/test/arg.dump +0 -0
- data/test/drb_fin.dump +0 -0
- data/test/http.dump +0 -0
- data/test/ping.dump +0 -0
- data/test/ring.dump +0 -0
- data/test/test_drbdump.rb +283 -0
- data/test/test_drbdump_loader.rb +88 -0
- data/test/test_drbdump_message.rb +31 -0
- data/test/test_drbdump_message_result.rb +73 -0
- data/test/test_drbdump_message_send.rb +105 -0
- data/test/test_drbdump_statistic.rb +98 -0
- data/test/test_drbdump_statistics.rb +264 -0
- data/test/too_large_packet.pcap +0 -0
- metadata +183 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'marshal/structure'
|
2
|
+
|
3
|
+
##
|
4
|
+
# A DRb protocol message chunk loader.
|
5
|
+
#
|
6
|
+
# Based on DRb::DRbMessage
|
7
|
+
|
8
|
+
class DRbDump::Loader
|
9
|
+
|
10
|
+
##
|
11
|
+
# Base Loader error class
|
12
|
+
|
13
|
+
class Error < DRbDump::Error; end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Raised when the message content is missing or too short
|
17
|
+
|
18
|
+
class DataError < Error; end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Raised when the packet is too large
|
22
|
+
|
23
|
+
class TooLarge < Error; end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Raised when the packet is not large enough to complete a message
|
27
|
+
|
28
|
+
class Premature < Error; end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Raised when the message size is incorrect or missing
|
32
|
+
|
33
|
+
class SizeError < Error; end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Creates a new loader with the given +config+ Hash. The loader uses only
|
37
|
+
# the :load_limit key to limit the maximum message size.
|
38
|
+
|
39
|
+
def initialize config
|
40
|
+
@load_limit = config[:load_limit]
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Returns the next component from a DRb message +stream+ as a
|
45
|
+
# Marshal::Structure object.
|
46
|
+
|
47
|
+
def load stream
|
48
|
+
begin
|
49
|
+
size = stream.read 4
|
50
|
+
rescue => e
|
51
|
+
raise SizeError, e.message, e.backtrace
|
52
|
+
end
|
53
|
+
|
54
|
+
raise SizeError, 'connection closed' unless size
|
55
|
+
raise Premature, 'header' if size.size < 4
|
56
|
+
|
57
|
+
size, = size.unpack 'N'
|
58
|
+
|
59
|
+
raise TooLarge, "#{size} bytes (#{@load_limit} allowed)" if
|
60
|
+
size >= @load_limit
|
61
|
+
|
62
|
+
begin
|
63
|
+
data = stream.read size
|
64
|
+
rescue => e
|
65
|
+
raise DataError, e.message, e.backtrace
|
66
|
+
end
|
67
|
+
|
68
|
+
raise DataError, 'connection closed' unless data
|
69
|
+
raise Premature, 'Marshal' if data.bytesize < size
|
70
|
+
|
71
|
+
Marshal::Structure.new data
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
##
|
2
|
+
# Contains common parts of MessageSend and MessageResult
|
3
|
+
|
4
|
+
class DRbDump::Message
|
5
|
+
|
6
|
+
##
|
7
|
+
# Creates the appropriate message instance from the next +packet+ which was
|
8
|
+
# captured by +drbdump+ on the given +stream+.
|
9
|
+
|
10
|
+
def self.from_stream drbdump, packet, stream
|
11
|
+
loader = drbdump.loader
|
12
|
+
|
13
|
+
first_chunk = loader.load stream
|
14
|
+
|
15
|
+
case first_chunk.load
|
16
|
+
when nil, Integer then
|
17
|
+
DRbDump::MessageSend.new drbdump, packet, first_chunk, stream
|
18
|
+
when true, false then
|
19
|
+
DRbDump::MessageResult.new drbdump, packet, first_chunk, stream
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Initializes a message from +packet+ captured by a +drbdump+
|
25
|
+
|
26
|
+
def initialize drbdump, packet
|
27
|
+
@drbdump = drbdump
|
28
|
+
@loader = drbdump.loader
|
29
|
+
@packet = packet
|
30
|
+
@statistics = drbdump.statistics
|
31
|
+
|
32
|
+
@source = nil
|
33
|
+
@destination = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# The resolved destination for the message.
|
38
|
+
|
39
|
+
def destination
|
40
|
+
return @destination if @destination
|
41
|
+
|
42
|
+
resolve_addresses
|
43
|
+
|
44
|
+
@destination
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Resolves source and destination addresses
|
49
|
+
|
50
|
+
def resolve_addresses # :nodoc:
|
51
|
+
resolver = @drbdump.resolver
|
52
|
+
|
53
|
+
source = @packet.source resolver
|
54
|
+
@source = "\"druby://#{source.sub(/\.(\d+)$/, ':\1')}\""
|
55
|
+
|
56
|
+
destination = @packet.destination resolver
|
57
|
+
@destination = "\"druby://#{destination.sub(/\.(\d+)$/, ':\1')}\""
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# The resolved source of the message
|
62
|
+
|
63
|
+
def source
|
64
|
+
return @source if @source
|
65
|
+
|
66
|
+
resolve_addresses
|
67
|
+
|
68
|
+
@source
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,84 @@
|
|
1
|
+
##
|
2
|
+
# Wraps a DRb message-result after consuming it from a stream.
|
3
|
+
|
4
|
+
class DRbDump::MessageResult < DRbDump::Message
|
5
|
+
|
6
|
+
##
|
7
|
+
# Creates a new MessageResult for the creating +drbdump+ instance. The last
|
8
|
+
# packet in the message is +packet+ and the Marshal::Structure for the
|
9
|
+
# result type is +status+. The rest of the message will be loaded from
|
10
|
+
# +stream+.
|
11
|
+
|
12
|
+
def initialize drbdump, packet, status, stream
|
13
|
+
super drbdump, packet
|
14
|
+
|
15
|
+
@result = nil
|
16
|
+
@status = nil
|
17
|
+
@stream = stream
|
18
|
+
|
19
|
+
@raw_result = @loader.load stream
|
20
|
+
@raw_status = status
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# The number of allocations required to load the result.
|
25
|
+
|
26
|
+
def allocations
|
27
|
+
@raw_status.count_allocations + @raw_result.count_allocations
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Prints the message information to standard output
|
32
|
+
|
33
|
+
def display
|
34
|
+
update_statistics
|
35
|
+
|
36
|
+
return if @drbdump.quiet
|
37
|
+
|
38
|
+
message = status ? 'success' : 'exception'
|
39
|
+
arrow = status ? "\u21d0" : "\u2902"
|
40
|
+
timestamp = self.timestamp.strftime DRbDump::TIMESTAMP_FORMAT
|
41
|
+
|
42
|
+
puts "%s %s %s %s %s: %s" % [
|
43
|
+
timestamp, destination, arrow, source, message, result
|
44
|
+
]
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# The loaded result object
|
49
|
+
|
50
|
+
def result
|
51
|
+
return @result if @result
|
52
|
+
|
53
|
+
result = @drbdump.load_marshal_data @raw_result
|
54
|
+
|
55
|
+
@result = if DRb::DRbObject === result then
|
56
|
+
"(\"druby://#{result.__drburi}\", #{result.__drbref})"
|
57
|
+
else
|
58
|
+
result.inspect
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# The loaded status object
|
64
|
+
|
65
|
+
def status
|
66
|
+
@status ||= @raw_status.load
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# The timestamp of the last packet in the result
|
71
|
+
|
72
|
+
def timestamp
|
73
|
+
@packet.timestamp
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Updates the drbdump's statistics with information from this result.
|
78
|
+
|
79
|
+
def update_statistics # :nodoc:
|
80
|
+
@statistics.add_result self
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
@@ -0,0 +1,146 @@
|
|
1
|
+
##
|
2
|
+
# Wraps a DRb message-send after consuming it from a stream.
|
3
|
+
|
4
|
+
class DRbDump::MessageSend < DRbDump::Message
|
5
|
+
|
6
|
+
##
|
7
|
+
# The number of arguments, not including the block
|
8
|
+
|
9
|
+
attr_reader :argc
|
10
|
+
|
11
|
+
##
|
12
|
+
# The arguments, each as a Marshal::Structure
|
13
|
+
|
14
|
+
attr_reader :raw_argv
|
15
|
+
|
16
|
+
##
|
17
|
+
# The block as a Marshal::Structure
|
18
|
+
|
19
|
+
attr_reader :raw_block
|
20
|
+
|
21
|
+
##
|
22
|
+
# The message sent as a Marshal::Structure
|
23
|
+
|
24
|
+
attr_reader :raw_message
|
25
|
+
|
26
|
+
##
|
27
|
+
# Creates a new MessageSend for the creating +drbdump+ instance. The last
|
28
|
+
# packet in the message is +packet+ and the Marshal::Structure for the first
|
29
|
+
# argument is +receiver+. The rest of the message will be loaded from
|
30
|
+
# +stream+.
|
31
|
+
|
32
|
+
def initialize drbdump, packet, receiver, stream
|
33
|
+
super drbdump, packet
|
34
|
+
|
35
|
+
@argc = nil
|
36
|
+
@argv = nil
|
37
|
+
@block = nil
|
38
|
+
@message = nil
|
39
|
+
@raw_receiver = receiver
|
40
|
+
@stream = stream
|
41
|
+
|
42
|
+
load_message if stream
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# The number of allocations required to load the message.
|
47
|
+
|
48
|
+
def allocations
|
49
|
+
allocations = 0
|
50
|
+
|
51
|
+
allocations += @raw_receiver.count_allocations
|
52
|
+
allocations += @raw_message.count_allocations
|
53
|
+
@raw_argv.each { |arg| allocations += arg.count_allocations }
|
54
|
+
allocations += @raw_block.count_allocations
|
55
|
+
|
56
|
+
allocations
|
57
|
+
end
|
58
|
+
|
59
|
+
##
|
60
|
+
# A string containing all loaded arguments including the block.
|
61
|
+
|
62
|
+
def arguments
|
63
|
+
arguments = argv.map { |obj| obj.inspect }
|
64
|
+
(arguments << '&block') if block
|
65
|
+
arguments.join ', '
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Number of arguments including the block
|
70
|
+
|
71
|
+
def argument_count
|
72
|
+
@argc + (block ? 1 : 0)
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# The loaded arguments
|
77
|
+
|
78
|
+
def argv
|
79
|
+
@argv ||= @raw_argv.map { |obj| @drbdump.load_marshal_data obj }
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# The loaded block
|
84
|
+
|
85
|
+
def block
|
86
|
+
@block ||= @raw_block.load
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Prints the message information to standard output
|
91
|
+
|
92
|
+
def display
|
93
|
+
update_statistics
|
94
|
+
|
95
|
+
return if @drbdump.quiet
|
96
|
+
|
97
|
+
timestamp = self.timestamp.strftime DRbDump::TIMESTAMP_FORMAT
|
98
|
+
|
99
|
+
puts "%s %s \u21d2 (%s, %p).%s(%s)" % [
|
100
|
+
timestamp, source, destination, receiver, message, arguments
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Returns the message, arguments and block for the DRb message-send in
|
106
|
+
# +stream+.
|
107
|
+
|
108
|
+
def load_message # :nodoc:
|
109
|
+
@raw_message = @loader.load @stream
|
110
|
+
@argc = @loader.load(@stream).load
|
111
|
+
@raw_argv = @argc.times.map { @loader.load @stream }
|
112
|
+
@raw_block = @loader.load @stream
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# The loaded message
|
117
|
+
|
118
|
+
def message
|
119
|
+
@message ||= @raw_message.load
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# The loaded receiver for the message
|
124
|
+
|
125
|
+
def receiver
|
126
|
+
@receiver ||= @raw_receiver.load
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Returns the timestamp for the first packet in the incomplete stream for
|
131
|
+
# +packet+ or the packet's timestamp if this is the only packet in the
|
132
|
+
# stream.
|
133
|
+
|
134
|
+
def timestamp
|
135
|
+
@drbdump.incomplete_timestamps.delete(@packet.source) || @packet.timestamp
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# Updates the drbdump's statistics with information from this message.
|
140
|
+
|
141
|
+
def update_statistics # :nodoc:
|
142
|
+
@statistics.add_message_send self
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
##
|
2
|
+
# Stores the minimum, maximum, mean, count and standard deviation for a set of
|
3
|
+
# values but not the values themselves.
|
4
|
+
|
5
|
+
class DRbDump::Statistic
|
6
|
+
|
7
|
+
##
|
8
|
+
# The number of items in the set
|
9
|
+
|
10
|
+
attr_reader :count
|
11
|
+
|
12
|
+
##
|
13
|
+
# The maximum value added
|
14
|
+
|
15
|
+
attr_reader :max
|
16
|
+
|
17
|
+
##
|
18
|
+
# The mean of all values
|
19
|
+
|
20
|
+
attr_reader :mean
|
21
|
+
|
22
|
+
##
|
23
|
+
# The minimum value added
|
24
|
+
|
25
|
+
attr_reader :min
|
26
|
+
|
27
|
+
def initialize # :nodoc:
|
28
|
+
@M_2 = 0.0
|
29
|
+
@count = 0
|
30
|
+
@max = -Float::INFINITY
|
31
|
+
@mean = 0.0
|
32
|
+
@min = Float::INFINITY
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Adds +value+ to the set of values. Returns the number of values.
|
37
|
+
|
38
|
+
def add value
|
39
|
+
@min = value if value < @min
|
40
|
+
@max = value if value > @max
|
41
|
+
@count += 1
|
42
|
+
|
43
|
+
delta = value - @mean
|
44
|
+
@mean += delta / @count
|
45
|
+
@M_2 += delta * (value - @mean)
|
46
|
+
|
47
|
+
@count
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# The average of all values
|
52
|
+
|
53
|
+
alias average mean
|
54
|
+
|
55
|
+
##
|
56
|
+
# The maximum value added
|
57
|
+
|
58
|
+
alias maximum max
|
59
|
+
|
60
|
+
##
|
61
|
+
# The minimum value added
|
62
|
+
|
63
|
+
alias minimum min
|
64
|
+
|
65
|
+
##
|
66
|
+
# The sample variance for all values
|
67
|
+
|
68
|
+
def sample_variance
|
69
|
+
sv = @M_2 / (@count - 1)
|
70
|
+
return 0.0 if sv.nan?
|
71
|
+
sv
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# The standard deviation of all values
|
76
|
+
|
77
|
+
def standard_deviation
|
78
|
+
Math.sqrt sample_variance
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# An array containing the number of values in the set, the mean and the
|
83
|
+
# standard deviation
|
84
|
+
|
85
|
+
def to_a
|
86
|
+
[@count, @min, @mean, @max, standard_deviation]
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|