RFC 350 (v1) Advanced I/O (AIO)

2000-09-29 Thread Perl6 RFC Librarian

This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Advanced I/O (AIO)

=head1 VERSION

  Maintainer: Uri Guttman [EMAIL PROTECTED]
  Date: 29 Sept 2000
  Mailing List: [EMAIL PROTECTED]
  Number: 350
  Version: 1
  Status: Developing

=head1 ABSTRACT

This RFC describes a pragma and module which support an advanced I/O
subsystem. It is meant to be a centralized subsystem that supports a
wide range of I/O requirements, many of which are covered in other
RFCs. It doesn't add any new syntax or break any existing code.

=head1 DESCRIPTION

There are many way that coders want to do I/O in Perl and many I/O
sources as well. RFC 14 discusses ways to make open smarter and to have
handlers for each flavor. The goal is good, but it requires new syntax
and semantics for open. You have effectively multiple versions of open,
each with their own argument order. It also doesn't address asynchronous
I/O or events and callbacks. I don't see how to make a socket or http
connect and not block on the request.

This RFC addresses those issues in a Perl5 way by creating a new class
with attribute based methods. This allows use to add new ways to do open
and I/O and not have to learn specialized argument formats. The style is
very similar to IO:: now but more generalized and tightly integrated in
the core. This is why I choose to call it Advanced I/O (AIO).

The main pragma will be 'use aio' and it will allow the coder to control
and load various components. I won't have the time to specify all of
them but think along the lines of RFC 14, LWP, libnet, IO::*,
LWP::Parallel, etc. Supporting them all under this single pardigm is
simple as you don't need to know more then the minimum attributes to get
your job done. Also as I have coverd some in RFC 47, many of the
attributes will have well chosen defaults which allow for shorter
argument lists for common situations. For example, instead of

$sock = IO::Socket::INET-new(PeerAddr = 'www.perl.org',
  PeerPort = 'http(80)',
  Proto= 'tcp');

you would do:

$sock = AIO::Open( Host = 'www.perl.org',
   Port = 80 ) ;

TCP would be the default protocol as it is much more common than UDP,
and it would know it is a socket connection because of the Host/Port
attributes.

Similarly for LWP you would just do:

$sock = AIO::Open( Url = 'http://www.perl.org' ) ;

If you refer to a special attribute, it can cause the appropriate
module to be loaded at runtime. In the above case the AIO::LWP (or
whatever it is called) would get loaded and then it would be passed the
open call.

One critical feature of AIO is direct support of asynchronous I/O
(including connections, server accepts, and real asynchronous file
I/O). There is no special interface required, you just specify a
callback attribute. That makes the request automatically non-blocking
and registers the event for you. You have to had previously specified an
event dispatch method (with use event or use aio) or it is a runtime
error.

Assuming an object $foo in package Foo, the above calls can be done with
asynchronous callbacks (see RFC 321 for more on callbacks) like this:


$event = AIO::Open( Host = 'www.perl.org',
Port = 80
Callback = $obj  ) ;


$event = AIO::Open( Url = 'http://www.perl.org/index.html',
Callback = $obj  ) ;


Package Foo ;

sub Connected {

my( $self, $socket ) = @_ ;

print "i am connected to perl.org\n" ;
}

sub Url_gotten {

my( $self, $socket ) = @_ ;

print $socket-read( 8096 ) ;
}

Here is an asynchronous file read :

$event = AIO::Read( Fd = $fh,
Count = 1000,
Callback = \read_handler ) ;

sub read_handler {

my( $read_data ) = @_ ;

print "i read [$read_data]\n" ;
}

The callback method names are the default ones (we can pick better ones
but I am under deadline pressure!) or you can choose your own. Timeouts
can also be set with their own method names or defualt ones:

$event = AIO::Open( Url = 'http://www.perl.org/index.html',
Callback= $obj,
Method  = 'Url_Ready'
Timeout = 10
Timeout_Method = 'URL_timeout' ) ;

So you see, the same simple syntax and a consistant API lets you do
blocking and non-blocking connect, I/O and timers. No need to learn
IO::, LWP and LWP::Parallel and IO::Select. All of them are covered in
under this approach and adding new attributes is easy and won't conflict
with other code written to this specification.

There is much more than can be desribed and I hope to have a 

Re: RFC 350 (v1) Advanced I/O (AIO)

2000-09-29 Thread Nathan Wiger

 you would do:
 
 $sock = AIO::Open( Host = 'www.perl.org',
Port = 80 ) ;

 Similarly for LWP you would just do:
 
 $sock = AIO::Open( Url = 'http://www.perl.org' ) ;

 $event = AIO::Open( Host = 'www.perl.org',
 Port = 80
 Callback = $obj  ) ;
 
 $event = AIO::Open( Url = 'http://www.perl.org/index.html',
 Callback = $obj  ) ;

I like this overall. Very nice.

One of the goals in RFC 14, and the reason why I chose to go the
"handler" route, is to make it look like open() had just been beefed up:

   $file = open "/etc/motd";
   $dir  = open dir "/usr/local";
   $http = open "http://www.yahoo.com";

However, the under-the-hood implementation of dir-open and http-open
is not explored; I was trying to create a consistent user-level
interface that does not require the complex syntax shown above. And from
this angle, I think RFC 14 has a lot to offer.

But, one thing that I think is worth exploring is how we could merge
this ideas, since I think the AIO system could well be a very viable
implementation. One thing I could see is ditching the handler idea and
instead just having people use URL's:

   $file = open "/etc/motd";
   $dir  = open "dir:/usr/local";
   $dir  = opendir "/usr/local";   # legacy shortcut
   $http = open "http://www.yahoo.com";

The CORE::open would be smart enough to then dispatch to the underlying
AIO-open (or whatever) and do something akin what you've listed above.

I like the AIO idea; if we could stick it under the hood (but still
accessible, like IO::, if you really want to use it directly), I could
see it implementing Perl 6 IO.

One last thing: I could see a class hierarchy as being potentially most
effective for something like this; perhaps you could have AIO::HTTP,
AIO::File, AIO::Dir, and so on, with the main AIO class serving as the
base/dispatch class.

-Nate