… | |
… | |
23 | my @result = $cv->wait; |
23 | my @result = $cv->wait; |
24 | |
24 | |
25 | =head1 DESCRIPTION |
25 | =head1 DESCRIPTION |
26 | |
26 | |
27 | This module implements an alternative "event dispatcher" for Net::SNMP, |
27 | This module implements an alternative "event dispatcher" for Net::SNMP, |
28 | using AnyEvent as a backend. |
28 | using AnyEvent as a backend. This integrates Net::SNMP into AnyEvent. That |
29 | |
29 | means you can make non-blocking Net::SNMP calls and as long as other |
30 | This integrates Net::SNMP into AnyEvent: You can make non-blocking |
30 | parts of your program also use AnyEvent (or some event loop supported by |
31 | Net::SNMP calls and as long as other parts of your program also use |
31 | AnyEvent), they will run in parallel. |
32 | AnyEvent (or some event loop supported by AnyEvent), they will run in |
|
|
33 | parallel. |
|
|
34 | |
32 | |
35 | Also, the Net::SNMP scheduler is very inefficient with respect to both CPU |
33 | Also, the Net::SNMP scheduler is very inefficient with respect to both CPU |
36 | and memory usage. Most AnyEvent backends (including the pure-perl backend) |
34 | and memory usage. Most AnyEvent backends (including the pure-perl backend) |
37 | fare much better than the Net::SNMP dispatcher. |
35 | fare much better than the Net::SNMP dispatcher. |
38 | |
36 | |
|
|
37 | Another major added feature of this module over Net::SNMP is automatic |
|
|
38 | rate-adjustments: Net::SNMP is so slow that firing a few thousand |
|
|
39 | requests can cause many timeouts simply because Net::SNMP cannot process |
|
|
40 | the replies in time. This module automatically adapts the send rate to |
|
|
41 | avoid false timeouts caused by slow reply processing. |
|
|
42 | |
39 | A potential disadvantage is that replacing the dispatcher is not at all |
43 | A potential disadvantage of this module is that replacing the dispatcher |
40 | a documented thing to do, so future changes in Net::SNP might break this |
44 | is not at all a documented thing to do, so future changes in Net::SNMP |
41 | module (or the many similar ones). |
45 | might break this module (or the many similar ones). |
42 | |
46 | |
43 | This module does not export anything and does not require you to do |
47 | This module does not export anything and does not require you to do |
44 | anything special apart from loading it I<before doing any non-blocking |
48 | anything special apart from loading it I<before doing any non-blocking |
45 | requests with Net::SNMP>. It is recommended but not required to load this |
49 | requests with Net::SNMP>. It is recommended but not required to load this |
46 | module before C<Net::SNMP>. |
50 | module before C<Net::SNMP>. |
… | |
… | |
65 | case, this can lead to packet loss, when the receive queue overflows and |
69 | case, this can lead to packet loss, when the receive queue overflows and |
66 | the kernel can no longer accept new packets. |
70 | the kernel can no longer accept new packets. |
67 | |
71 | |
68 | To avoid this, you can (and should) limit the number of outstanding |
72 | To avoid this, you can (and should) limit the number of outstanding |
69 | requests to a number low enough so that parsing time doesn't introduce |
73 | requests to a number low enough so that parsing time doesn't introduce |
70 | noticable delays. |
74 | noticeable delays. |
71 | |
75 | |
72 | Unfortunately, this number depends not only on processing speed and load |
76 | Unfortunately, this number depends not only on processing speed and load |
73 | of the machine running Net::SNMP, but also on the network latency and the |
77 | of the machine running Net::SNMP, but also on the network latency and the |
74 | speed of your SNMP agents. |
78 | speed of your SNMP agents. |
75 | |
79 | |
76 | AnyEvent::SNMP tries to dynamically adjust this number dynamically upwards |
80 | AnyEvent::SNMP tries to dynamically adjust this number upwards and |
77 | and downwards. |
81 | downwards. |
78 | |
82 | |
79 | Increasing C<$MAX_OUTSTANDING> will not automatically use the |
83 | Increasing C<$MAX_OUTSTANDING> will not automatically use the |
80 | extra request slots. To increase C<$MAX_OUTSTANDING> and make |
84 | extra request slots. To increase C<$MAX_OUTSTANDING> and make |
81 | C<AnyEvent::SNMP> make use of the extra paralellity, call |
85 | C<AnyEvent::SNMP> make use of the extra parallelity, call |
82 | C<AnyEvent::SNMP::set_max_outstanding> with the new value, e.g.: |
86 | C<AnyEvent::SNMP::set_max_outstanding> with the new value, e.g.: |
83 | |
87 | |
84 | AnyEvent::SNMP::set_max_outstanding 500; |
88 | AnyEvent::SNMP::set_max_outstanding 500; |
85 | |
89 | |
86 | Although due to the dynamic adjustment, this might have little lasting |
90 | Although due to the dynamic adjustment, this might have little lasting |
… | |
… | |
99 | When AnyEvent::SNMP handles $MAX_RECVQUEUE or more packets per iteration |
103 | When AnyEvent::SNMP handles $MAX_RECVQUEUE or more packets per iteration |
100 | it will reduce $MAX_OUTSTANDING. If it handles less than $MIN_RECVQUEUE, |
104 | it will reduce $MAX_OUTSTANDING. If it handles less than $MIN_RECVQUEUE, |
101 | it increases $MAX_OUTSTANDING. |
105 | it increases $MAX_OUTSTANDING. |
102 | |
106 | |
103 | This has the result of adjusting the number of outstanding requests so that |
107 | This has the result of adjusting the number of outstanding requests so that |
104 | the recv queue is between the minimum and maximu, usually. |
108 | the recv queue is between the minimum and maximum, usually. |
105 | |
109 | |
106 | This algorithm works reasonably well as long as the responses, response |
110 | This algorithm works reasonably well as long as the responses, response |
107 | latencies and processing times are the same size per packet on average. |
111 | latencies and processing times are the same per packet on average. |
108 | |
112 | |
109 | =back |
113 | =back |
110 | |
114 | |
111 | =head1 COMPATIBILITY |
115 | =head1 COMPATIBILITY |
112 | |
116 | |
… | |
… | |
131 | |
135 | |
132 | =cut |
136 | =cut |
133 | |
137 | |
134 | package AnyEvent::SNMP; |
138 | package AnyEvent::SNMP; |
135 | |
139 | |
136 | no warnings; |
140 | use common::sense; |
137 | use strict qw(subs vars); |
|
|
138 | |
141 | |
139 | # it is possible to do this without loading |
142 | # it is possible to do this without loading |
140 | # Net::SNMP::Dispatcher, but much more awkward. |
143 | # Net::SNMP::Dispatcher, but much more awkward. |
141 | use Net::SNMP::Dispatcher; |
144 | use Net::SNMP::Dispatcher; |
142 | |
145 | |
|
|
146 | # we could inherit fro Net:SNMP::Dispatcher, but since this is undocumented, |
|
|
147 | # I'd rather see it die (and reported) than silenty and subtly fail. |
|
|
148 | *msg_handle_alloc = \&Net::SNMP::Dispatcher::msg_handle_alloc; |
|
|
149 | |
143 | sub Net::SNMP::Dispatcher::instance { |
150 | sub Net::SNMP::Dispatcher::instance { |
144 | AnyEvent::SNMP:: |
151 | AnyEvent::SNMP:: |
145 | } |
152 | } |
146 | |
153 | |
147 | use Net::SNMP (); |
154 | use Net::SNMP (); |
148 | use AnyEvent (); |
155 | use AnyEvent (); |
149 | |
156 | |
150 | our $VERSION = '1.0'; |
157 | our $VERSION = '6.02'; |
151 | |
158 | |
152 | $Net::SNMP::DISPATCHER = instance Net::SNMP::Dispatcher; |
159 | $Net::SNMP::DISPATCHER = instance Net::SNMP::Dispatcher; |
153 | |
160 | |
154 | our $MESSAGE_PROCESSING = $Net::SNMP::Dispatcher::MESSAGE_PROCESSING; |
161 | our $MESSAGE_PROCESSING = $Net::SNMP::Dispatcher::MESSAGE_PROCESSING; |
155 | |
162 | |
… | |
… | |
250 | |
257 | |
251 | # Set the error if applicable. |
258 | # Set the error if applicable. |
252 | $msg->error ($MESSAGE_PROCESSING->error) if $MESSAGE_PROCESSING->error; |
259 | $msg->error ($MESSAGE_PROCESSING->error) if $MESSAGE_PROCESSING->error; |
253 | |
260 | |
254 | # Notify the command generator to process the response. |
261 | # Notify the command generator to process the response. |
255 | $msg->process_response_pdu; |
262 | # Net::SNMP calls process_response_pdu, which simply calls callback_execute, |
|
|
263 | # but some errors cause $msg to be of type Net::SNMP::Message, not Net::SMMP::PDU, |
|
|
264 | # so we call the underlying callback_execute method which exists on both and |
|
|
265 | # seems to do the right thing. |
|
|
266 | $msg->callback_execute; |
256 | |
267 | |
257 | # Cancel the timeout. |
268 | # Cancel the timeout. |
258 | my $rtimeout_w = $msg->timeout_id; |
269 | my $rtimeout_w = $msg->timeout_id; |
259 | if ($$rtimeout_w) { |
270 | if ($$rtimeout_w) { |
260 | undef $$rtimeout_w; |
271 | undef $$rtimeout_w; |
… | |
… | |
334 | kick_job; |
345 | kick_job; |
335 | |
346 | |
336 | 1 |
347 | 1 |
337 | } |
348 | } |
338 | |
349 | |
339 | sub activate($) { |
350 | sub loop($) { |
340 | while ($BUSY) { |
351 | while ($BUSY) { |
341 | $DONE = AE::cv; |
352 | $DONE = AE::cv; |
342 | $DONE->recv; |
353 | $DONE->recv; |
343 | undef $DONE; |
354 | undef $DONE; |
344 | } |
355 | } |
345 | } |
356 | } |
346 | |
357 | |
|
|
358 | *activate = \&loop; # 5.x compatibility? |
|
|
359 | *listen = \&loop; # 5.x compatibility? |
|
|
360 | |
347 | sub one_event($) { |
361 | sub one_event($) { |
348 | # should not ever be used |
362 | # should not ever be used |
349 | AnyEvent->one_event; #d# todo |
363 | AnyEvent->one_event; #d# todo |
350 | } |
364 | } |
351 | |
365 | |
352 | sub set_max_outstanding($) { |
366 | sub set_max_outstanding($) { |
353 | $MAX_OUTSTANDING = $_[0]; |
367 | $MAX_OUTSTANDING = $_[0]; |
354 | kick_job; |
368 | kick_job; |
355 | } |
369 | } |
356 | |
370 | |
|
|
371 | # not provided yet: |
|
|
372 | # schedule # apparently only used by Net::SNMP::Dispatcher itself |
|
|
373 | # register # apparently only used by Net::SNMP::Dispatcher itself |
|
|
374 | # deregister # apparently only used by Net::SNMP::Dispatcher itself |
|
|
375 | # cancel # apparently only used by Net::SNMP::Dispatcher itself |
|
|
376 | # return_response_pdu # apparently not used at all? |
|
|
377 | # error # only used by Net::SNMP::Dispatcher itself? |
|
|
378 | # debug # only used by Net::SNMP::Dispatcher itself? |
|
|
379 | |
357 | =head1 SEE ALSO |
380 | =head1 SEE ALSO |
358 | |
381 | |
359 | L<AnyEvent>, L<Net::SNMP>, L<Net::SNMP::XS>, L<Net::SNMP::EV>. |
382 | L<AnyEvent>, L<Net::SNMP>, L<Net::SNMP::XS>, L<Net::SNMP::EV>. |
360 | |
383 | |
361 | =head1 AUTHOR |
384 | =head1 AUTHOR |