drbdump 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+