ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/AnyEvent-SNMP/SNMP.pm
(Generate patch)

Comparing cvsroot/AnyEvent-SNMP/SNMP.pm (file contents):
Revision 1.8 by root, Wed Jan 6 10:25:54 2010 UTC vs.
Revision 1.12 by root, Sun Apr 15 11:02:07 2012 UTC

23 my @result = $cv->wait; 23 my @result = $cv->wait;
24 24
25=head1 DESCRIPTION 25=head1 DESCRIPTION
26 26
27This module implements an alternative "event dispatcher" for Net::SNMP, 27This module implements an alternative "event dispatcher" for Net::SNMP,
28using AnyEvent as a backend. 28using AnyEvent as a backend. This integrates Net::SNMP into AnyEvent. That
29 29means you can make non-blocking Net::SNMP calls and as long as other
30This integrates Net::SNMP into AnyEvent: You can make non-blocking 30parts of your program also use AnyEvent (or some event loop supported by
31Net::SNMP calls and as long as other parts of your program also use 31AnyEvent), they will run in parallel.
32AnyEvent (or some event loop supported by AnyEvent), they will run in
33parallel.
34 32
35Also, the Net::SNMP scheduler is very inefficient with respect to both CPU 33Also, the Net::SNMP scheduler is very inefficient with respect to both CPU
36and memory usage. Most AnyEvent backends (including the pure-perl backend) 34and memory usage. Most AnyEvent backends (including the pure-perl backend)
37fare much better than the Net::SNMP dispatcher. 35fare much better than the Net::SNMP dispatcher.
38 36
37Another major added fetaure of this module over Net::SNMP is automatic
38rate-adjustments: Net::SNMP is so slow that firing a few thousand
39requests can cause many timeouts simply because Net::SNMP cannot process
40the replies in time. This module automatically adapts the send rate to
41avoid false timeouts caused by slow reply processing.
42
39A potential disadvantage is that replacing the dispatcher is not at all 43A potential disadvantage of this module is that replacing the dispatcher
40a documented thing to do, so future changes in Net::SNP might break this 44is not at all a documented thing to do, so future changes in Net::SNP
41module (or the many similar ones). 45might break this module (or the many similar ones).
42 46
43This module does not export anything and does not require you to do 47This module does not export anything and does not require you to do
44anything special apart from loading it I<before doing any non-blocking 48anything special apart from loading it I<before doing any non-blocking
45requests with Net::SNMP>. It is recommended but not required to load this 49requests with Net::SNMP>. It is recommended but not required to load this
46module before C<Net::SNMP>. 50module before C<Net::SNMP>.
71 75
72Unfortunately, this number depends not only on processing speed and load 76Unfortunately, this number depends not only on processing speed and load
73of the machine running Net::SNMP, but also on the network latency and the 77of the machine running Net::SNMP, but also on the network latency and the
74speed of your SNMP agents. 78speed of your SNMP agents.
75 79
76AnyEvent::SNMP tries to dynamically adjust this number dynamically upwards 80AnyEvent::SNMP tries to dynamically adjust this number upwards and
77and downwards. 81downwards.
78 82
79Increasing C<$MAX_OUTSTANDING> will not automatically use the 83Increasing C<$MAX_OUTSTANDING> will not automatically use the
80extra request slots. To increase C<$MAX_OUTSTANDING> and make 84extra request slots. To increase C<$MAX_OUTSTANDING> and make
81C<AnyEvent::SNMP> make use of the extra paralellity, call 85C<AnyEvent::SNMP> make use of the extra paralellity, call
82C<AnyEvent::SNMP::set_max_outstanding> with the new value, e.g.: 86C<AnyEvent::SNMP::set_max_outstanding> with the new value, e.g.:
131 135
132=cut 136=cut
133 137
134package AnyEvent::SNMP; 138package AnyEvent::SNMP;
135 139
136no warnings; 140use common::sense;
137use 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.
141use Net::SNMP::Dispatcher; 144use 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
143sub Net::SNMP::Dispatcher::instance { 150sub Net::SNMP::Dispatcher::instance {
144 AnyEvent::SNMP:: 151 AnyEvent::SNMP::
145} 152}
146 153
147use Net::SNMP (); 154use Net::SNMP ();
148use AnyEvent (); 155use AnyEvent ();
149 156
150our $VERSION = '1.0'; 157our $VERSION = '6.0';
151 158
152$Net::SNMP::DISPATCHER = instance Net::SNMP::Dispatcher; 159$Net::SNMP::DISPATCHER = instance Net::SNMP::Dispatcher;
153 160
154our $MESSAGE_PROCESSING = $Net::SNMP::Dispatcher::MESSAGE_PROCESSING; 161our $MESSAGE_PROCESSING = $Net::SNMP::Dispatcher::MESSAGE_PROCESSING;
155 162
159our @QUEUE; 166our @QUEUE;
160our $MAX_OUTSTANDING = 50; 167our $MAX_OUTSTANDING = 50;
161our $MIN_RECVQUEUE = 8; 168our $MIN_RECVQUEUE = 8;
162our $MAX_RECVQUEUE = 64; 169our $MAX_RECVQUEUE = 64;
163 170
164sub kick_job; # also --$BUSY 171sub kick_job;
165 172
166sub _send_pdu { 173sub _send_pdu {
167 my ($pdu, $retries) = @_; 174 my ($pdu, $retries) = @_;
168 175
169 # mostly copied from Net::SNMP::Dispatch 176 # mostly copied from Net::SNMP::Dispatch
171 # Pass the PDU to Message Processing so that it can 178 # Pass the PDU to Message Processing so that it can
172 # create the new outgoing message. 179 # create the new outgoing message.
173 my $msg = $MESSAGE_PROCESSING->prepare_outgoing_msg ($pdu); 180 my $msg = $MESSAGE_PROCESSING->prepare_outgoing_msg ($pdu);
174 181
175 if (!defined $msg) { 182 if (!defined $msg) {
183 --$BUSY;
176 kick_job; 184 kick_job;
177 # Inform the command generator about the Message Processing error. 185 # Inform the command generator about the Message Processing error.
178 $pdu->status_information ($MESSAGE_PROCESSING->error); 186 $pdu->status_information ($MESSAGE_PROCESSING->error);
179 return; 187 return;
180 } 188 }
189 my $retry_w; $retry_w = AE::timer $pdu->timeout, 0, sub { 197 my $retry_w; $retry_w = AE::timer $pdu->timeout, 0, sub {
190 undef $retry_w; 198 undef $retry_w;
191 _send_pdu ($pdu, $retries); 199 _send_pdu ($pdu, $retries);
192 }; 200 };
193 } else { 201 } else {
202 --$BUSY;
194 kick_job; 203 kick_job;
195 } 204 }
196 205
197 # Inform the command generator about the send() error. 206 # Inform the command generator about the send() error.
198 $pdu->status_information ($msg->error); 207 $pdu->status_information ($msg->error);
255 # Cancel the timeout. 264 # Cancel the timeout.
256 my $rtimeout_w = $msg->timeout_id; 265 my $rtimeout_w = $msg->timeout_id;
257 if ($$rtimeout_w) { 266 if ($$rtimeout_w) {
258 undef $$rtimeout_w; 267 undef $$rtimeout_w;
259 268
269 --$BUSY;
260 kick_job; 270 kick_job;
261 271
262 unless (--$TRANSPORT[$fileno][0]) { 272 unless (--$TRANSPORT[$fileno][0]) {
263 delete $TRANSPORT[$fileno]; 273 delete $TRANSPORT[$fileno];
264 return; 274 return;
286 _send_pdu ($pdu, $retries); 296 _send_pdu ($pdu, $retries);
287 } else { 297 } else {
288 $MESSAGE_PROCESSING->msg_handle_delete ($pdu->msg_id); 298 $MESSAGE_PROCESSING->msg_handle_delete ($pdu->msg_id);
289 $pdu->status_information ("No response from remote host '%s'", $pdu->hostname); 299 $pdu->status_information ("No response from remote host '%s'", $pdu->hostname);
290 300
301 --$BUSY;
291 kick_job; 302 kick_job;
292 } 303 }
293 }) 304 })
294 ); 305 );
295 } else { 306 } else {
307 --$BUSY;
296 kick_job; 308 kick_job;
297 } 309 }
298} 310}
299 311
300sub kick_job { 312sub kick_job {
301 --$BUSY;
302
303 while ($BUSY < $MAX_OUTSTANDING) { 313 while ($BUSY < $MAX_OUTSTANDING) {
304 my $pdu = shift @QUEUE 314 my $pdu = shift @QUEUE
305 or last; 315 or last;
306 316
307 ++$BUSY; 317 ++$BUSY;
308
309 _send_pdu $pdu, $pdu->retries; 318 _send_pdu $pdu, $pdu->retries;
310 } 319 }
311 320
312 $DONE and $DONE->() unless $BUSY; 321 $DONE and $DONE->() unless $BUSY;
313} 322}
320 if ($delay > 0) { 329 if ($delay > 0) {
321 ++$BUSY; 330 ++$BUSY;
322 my $delay_w; $delay_w = AE::timer $delay, 0, sub { 331 my $delay_w; $delay_w = AE::timer $delay, 0, sub {
323 undef $delay_w; 332 undef $delay_w;
324 push @QUEUE, $pdu; 333 push @QUEUE, $pdu;
334 --$BUSY;
325 kick_job; 335 kick_job;
326 }; 336 };
327 return 1; 337 return 1;
328 } 338 }
329 339
331 kick_job; 341 kick_job;
332 342
333 1 343 1
334} 344}
335 345
336sub activate($) { 346sub loop($) {
337 while ($BUSY) { 347 while ($BUSY) {
338 $DONE = AE::cv; 348 $DONE = AE::cv;
339 $DONE->recv; 349 $DONE->recv;
340 undef $DONE; 350 undef $DONE;
341 } 351 }
342} 352}
343 353
354*activate = \&loop; # 5.x compatibility?
355*listen = \&loop; # 5.x compatibility?
356
344sub one_event($) { 357sub one_event($) {
358 # should not ever be used
345 AnyEvent->one_event; #d# todo 359 AnyEvent->one_event; #d# todo
346} 360}
347 361
348sub set_max_outstanding($) { 362sub set_max_outstanding($) {
349 $MAX_OUTSTANDING = $_[0]; 363 $MAX_OUTSTANDING = $_[0];
350
351 ++$BUSY; # kick_job decrements $BUSY
352 kick_job; 364 kick_job;
353} 365}
366
367# not provided yet:
368# schedule # apparently only used by Net::SNMP::Dispatcher itself
369# register # apparently only used by Net::SNMP::Dispatcher itself
370# deregister # apparently only used by Net::SNMP::Dispatcher itself
371# cancel # apparently only used by Net::SNMP::Dispatcher itself
372# return_response_pdu # apparently not used at all?
373# error # only used by Net::SNMP::Dispatcher itself?
374# debug # only used by Net::SNMP::Dispatcher itself?
354 375
355=head1 SEE ALSO 376=head1 SEE ALSO
356 377
357L<AnyEvent>, L<Net::SNMP>, L<Net::SNMP::XS>, L<Net::SNMP::EV>. 378L<AnyEvent>, L<Net::SNMP>, L<Net::SNMP::XS>, L<Net::SNMP::EV>.
358 379

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines