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.
@@ -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
+