IO-AIO

 view release on metacpan or  search on metacpan

AIO.pm  view on Meta::CPAN


During their existance, aio requests travel through the following states,
in order:

=over 4

=item ready

Immediately after a request is created it is put into the ready state,
waiting for a thread to execute it.

=item execute

A thread has accepted the request for processing and is currently
executing it (e.g. blocking in read).

=item pending

The request has been executed and is waiting for result processing.

While request submission and execution is fully asynchronous, result
processing is not and relies on the perl interpreter calling C<poll_cb>
(or another function with the same effect).

=item result

The request results are processed synchronously by C<poll_cb>.

The C<poll_cb> function will process all outstanding aio requests by
calling their callbacks, freeing memory associated with them and managing
any groups they are contained in.

=item done

Request has reached the end of its lifetime and holds no resources anymore
(except possibly for the Perl object, but its connection to the actual
aio request is severed and calling its methods will either do nothing or
result in a runtime error).

=back

=cut

package IO::AIO;

use Carp ();

use common::sense;

use base 'Exporter';

BEGIN {
   our $VERSION = 4.81;

   our @AIO_REQ = qw(aio_sendfile aio_seek aio_read aio_write aio_open aio_close
                     aio_stat aio_lstat aio_unlink aio_rmdir aio_readdir aio_readdirx
                     aio_scandir aio_symlink aio_readlink aio_realpath aio_fcntl aio_ioctl
                     aio_sync aio_fsync aio_syncfs aio_fdatasync aio_sync_file_range
                     aio_pathsync aio_readahead aio_fiemap aio_allocate
                     aio_rename aio_rename2 aio_link aio_move aio_copy aio_group
                     aio_nop aio_mknod aio_load aio_rmtree aio_mkdir aio_chown
                     aio_chmod aio_utime aio_truncate
                     aio_msync aio_mtouch aio_mlock aio_mlockall
                     aio_statvfs
                     aio_slurp
                     aio_wd);

   our @EXPORT = (@AIO_REQ, qw(aioreq_pri aioreq_nice));
   our @EXPORT_OK = qw(poll_fileno poll_cb poll_wait flush
                       min_parallel max_parallel max_idle idle_timeout
                       nreqs nready npending nthreads
                       max_poll_time max_poll_reqs
                       sendfile fadvise madvise
                       mmap munmap mremap munlock munlockall

                       accept4 tee splice pipe2 pipesize
                       fexecve mount umount memfd_create eventfd
                       timerfd_create timerfd_settime timerfd_gettime
                       pidfd_open pidfd_send_signal pidfd_getfd);

   push @AIO_REQ, qw(aio_busy); # not exported

   @IO::AIO::GRP::ISA = 'IO::AIO::REQ';

   require XSLoader;
   XSLoader::load ("IO::AIO", $VERSION);
}

=head1 FUNCTIONS

=head2 QUICK OVERVIEW

This section simply lists the prototypes most of the functions for
quick reference. See the following sections for function-by-function
documentation.

   aio_wd $pathname, $callback->($wd)
   aio_open $pathname, $flags, $mode, $callback->($fh)
   aio_close $fh, $callback->($status)
   aio_seek  $fh,$offset,$whence, $callback->($offs)
   aio_read  $fh,$offset,$length, $data,$dataoffset, $callback->($retval)
   aio_write $fh,$offset,$length, $data,$dataoffset, $callback->($retval)
   aio_sendfile $out_fh, $in_fh, $in_offset, $length, $callback->($retval)
   aio_readahead $fh,$offset,$length, $callback->($retval)
   aio_stat  $fh_or_path, $callback->($status)
   aio_lstat $fh, $callback->($status)
   aio_statvfs $fh_or_path, $callback->($statvfs)
   aio_utime $fh_or_path, $atime, $mtime, $callback->($status)
   aio_chown $fh_or_path, $uid, $gid, $callback->($status)
   aio_chmod $fh_or_path, $mode, $callback->($status)
   aio_truncate $fh_or_path, $offset, $callback->($status)
   aio_allocate $fh, $mode, $offset, $len, $callback->($status)
   aio_fiemap $fh, $start, $length, $flags, $count, $cb->(\@extents)
   aio_unlink $pathname, $callback->($status)
   aio_mknod $pathname, $mode, $dev, $callback->($status)
   aio_link $srcpath, $dstpath, $callback->($status)
   aio_symlink $srcpath, $dstpath, $callback->($status)
   aio_readlink $pathname, $callback->($link)
   aio_realpath $pathname, $callback->($path)
   aio_rename $srcpath, $dstpath, $callback->($status)
   aio_rename2 $srcpath, $dstpath, $flags, $callback->($status)
   aio_mkdir $pathname, $mode, $callback->($status)
   aio_rmdir $pathname, $callback->($status)
   aio_readdir $pathname, $callback->($entries)
   aio_readdirx $pathname, $flags, $callback->($entries, $flags)
      IO::AIO::READDIR_DENTS IO::AIO::READDIR_DIRS_FIRST
      IO::AIO::READDIR_STAT_ORDER IO::AIO::READDIR_FOUND_UNKNOWN
   aio_scandir $pathname, $maxreq, $callback->($dirs, $nondirs)
   aio_load $pathname, $data, $callback->($status)
   aio_copy $srcpath, $dstpath, $callback->($status)
   aio_move $srcpath, $dstpath, $callback->($status)
   aio_rmtree $pathname, $callback->($status)
   aio_fcntl $fh, $cmd, $arg, $callback->($status)
   aio_ioctl $fh, $request, $buf, $callback->($status)
   aio_sync $callback->($status)
   aio_syncfs $fh, $callback->($status)
   aio_fsync $fh, $callback->($status)
   aio_fdatasync $fh, $callback->($status)
   aio_sync_file_range $fh, $offset, $nbytes, $flags, $callback->($status)
   aio_pathsync $pathname, $callback->($status)
   aio_msync $scalar, $offset = 0, $length = undef, flags = MS_SYNC, $callback->($status)
   aio_mtouch $scalar, $offset = 0, $length = undef, flags = 0, $callback->($status)
   aio_mlock $scalar, $offset = 0, $length = undef, $callback->($status)
   aio_mlockall $flags, $callback->($status)
   aio_group $callback->(...)
   aio_nop $callback->()

   $prev_pri = aioreq_pri [$pri]
   aioreq_nice $pri_adjust

   IO::AIO::poll_wait
   IO::AIO::poll_cb
   IO::AIO::poll
   IO::AIO::flush
   IO::AIO::max_poll_reqs $nreqs
   IO::AIO::max_poll_time $seconds
   IO::AIO::min_parallel $nthreads
   IO::AIO::max_parallel $nthreads
   IO::AIO::max_idle $nthreads
   IO::AIO::idle_timeout $seconds
   IO::AIO::max_outstanding $maxreqs
   IO::AIO::nreqs
   IO::AIO::nready
   IO::AIO::npending
   IO::AIO::reinit

   $nfd = IO::AIO::get_fdlimit
   IO::AIO::min_fdlimit $nfd

AIO.pm  view on Meta::CPAN

whether a file handle or path was passed.

On success, the callback is passed a hash reference with the following
members: C<bsize>, C<frsize>, C<blocks>, C<bfree>, C<bavail>, C<files>,
C<ffree>, C<favail>, C<fsid>, C<flag> and C<namemax>. On failure, C<undef>
is passed.

The following POSIX IO::AIO::ST_* constants are defined: C<ST_RDONLY> and
C<ST_NOSUID>.

The following non-POSIX IO::AIO::ST_* flag masks are defined to
their correct value when available, or to C<0> on systems that do
not support them:  C<ST_NODEV>, C<ST_NOEXEC>, C<ST_SYNCHRONOUS>,
C<ST_MANDLOCK>, C<ST_WRITE>, C<ST_APPEND>, C<ST_IMMUTABLE>, C<ST_NOATIME>,
C<ST_NODIRATIME> and C<ST_RELATIME>.

Example: stat C</wd> and dump out the data if successful.

   aio_statvfs "/wd", sub {
      my $f = $_[0]
         or die "statvfs: $!";

      use Data::Dumper;
      say Dumper $f;
   };

   # result:
   {
      bsize   => 1024,
      bfree   => 4333064312,
      blocks  => 10253828096,
      files   => 2050765568,
      flag    => 4096,
      favail  => 2042092649,
      bavail  => 4333064312,
      ffree   => 2042092649,
      namemax => 255,
      frsize  => 1024,
      fsid    => 1810
   }

=item aio_utime $fh_or_path, $atime, $mtime, $callback->($status)

Works like perl's C<utime> function (including the special case of $atime
and $mtime being undef). Fractional times are supported if the underlying
syscalls support them.

When called with a pathname, uses utimensat(2) or utimes(2) if available,
otherwise utime(2). If called on a file descriptor, uses futimens(2)
or futimes(2) if available, otherwise returns ENOSYS, so this is not
portable.

Examples:

   # set atime and mtime to current time (basically touch(1)):
   aio_utime "path", undef, undef;
   # set atime to current time and mtime to beginning of the epoch:
   aio_utime "path", time, undef; # undef==0


=item aio_chown $fh_or_path, $uid, $gid, $callback->($status)

Works like perl's C<chown> function, except that C<undef> for either $uid
or $gid is being interpreted as "do not change" (but -1 can also be used).

Examples:

   # same as "chown root path" in the shell:
   aio_chown "path", 0, -1;
   # same as above:
   aio_chown "path", 0, undef;


=item aio_truncate $fh_or_path, $offset, $callback->($status)

Works like truncate(2) or ftruncate(2).


=item aio_allocate $fh, $mode, $offset, $len, $callback->($status)

Allocates or frees disk space according to the C<$mode> argument. See the
linux C<fallocate> documentation for details.

C<$mode> is usually C<0> or C<IO::AIO::FALLOC_FL_KEEP_SIZE> to allocate
space, or C<IO::AIO::FALLOC_FL_PUNCH_HOLE | IO::AIO::FALLOC_FL_KEEP_SIZE>,
to deallocate a file range.

IO::AIO also supports C<FALLOC_FL_COLLAPSE_RANGE>, to remove a range
(without leaving a hole), C<FALLOC_FL_ZERO_RANGE>, to zero a range,
C<FALLOC_FL_INSERT_RANGE> to insert a range and C<FALLOC_FL_UNSHARE_RANGE>
to unshare shared blocks (see your L<fallocate(2)> manpage).

The file system block size used by C<fallocate> is presumably the
C<f_bsize> returned by C<statvfs>, but different filesystems and filetypes
can dictate other limitations.

If C<fallocate> isn't available or cannot be emulated (currently no
emulation will be attempted), passes C<-1> and sets C<$!> to C<ENOSYS>.


=item aio_chmod $fh_or_path, $mode, $callback->($status)

Works like perl's C<chmod> function.


=item aio_unlink $pathname, $callback->($status)

Asynchronously unlink (delete) a file and call the callback with the
result code.


=item aio_mknod $pathname, $mode, $dev, $callback->($status)

[EXPERIMENTAL]

Asynchronously create a device node (or fifo). See mknod(2).

The only (POSIX-) portable way of calling this function is:

   aio_mknod $pathname, IO::AIO::S_IFIFO | $mode, 0, sub { ...

See C<aio_stat> for info about some potentially helpful extra constants
and functions.

=item aio_link $srcpath, $dstpath, $callback->($status)

Asynchronously create a new link to the existing object at C<$srcpath> at
the path C<$dstpath> and call the callback with the result code.


=item aio_symlink $srcpath, $dstpath, $callback->($status)

AIO.pm  view on Meta::CPAN

      my $fh = shift
         or return $grp->result (-1);

      aioreq_pri $pri;
      add $grp aio_read $fh, 0, (-s $fh), $$data, 0, sub {
         $grp->result ($_[0]);
      };
   };

   $grp
}

=item aio_copy $srcpath, $dstpath, $callback->($status)

Try to copy the I<file> (directories not supported as either source or
destination) from C<$srcpath> to C<$dstpath> and call the callback with
a status of C<0> (ok) or C<-1> (error, see C<$!>).

Existing destination files will be truncated.

This is a composite request that creates the destination file with
mode 0200 and copies the contents of the source file into it using
C<aio_sendfile>, followed by restoring atime, mtime, access mode and
uid/gid, in that order.

If an error occurs, the partial destination file will be unlinked, if
possible, except when setting atime, mtime, access mode and uid/gid, where
errors are being ignored.

=cut

sub aio_copy($$;$) {
   my ($src, $dst, $cb) = @_;

   my $pri = aioreq_pri;
   my $grp = aio_group $cb;

   aioreq_pri $pri;
   add $grp aio_open $src, O_RDONLY, 0, sub {
      if (my $src_fh = $_[0]) {
         my @stat = stat $src_fh; # hmm, might block over nfs?

         aioreq_pri $pri;
         add $grp aio_open $dst, O_CREAT | O_WRONLY | O_TRUNC, 0200, sub {
            if (my $dst_fh = $_[0]) {

               # best-effort preallocate
               aioreq_pri $pri;
               add $grp aio_allocate $dst_fh, IO::AIO::FALLOC_FL_KEEP_SIZE, 0, $stat[7], sub { };

               aioreq_pri $pri;
               add $grp aio_sendfile $dst_fh, $src_fh, 0, $stat[7], sub {
                  if ($_[0] == $stat[7]) {
                     $grp->result (0);
                     close $src_fh;

                     my $ch = sub {
                        aioreq_pri $pri;
                        add $grp aio_chmod $dst_fh, $stat[2] & 07777, sub {
                           aioreq_pri $pri;
                           add $grp aio_chown $dst_fh, $stat[4], $stat[5], sub {
                              aioreq_pri $pri;
                              add $grp aio_close $dst_fh;
                           }
                        };
                     };

                     aioreq_pri $pri;
                     add $grp aio_utime $dst_fh, $stat[8], $stat[9], sub {
                        if ($_[0] < 0 && $! == ENOSYS) {
                           aioreq_pri $pri;
                           add $grp aio_utime $dst, $stat[8], $stat[9], $ch;
                        } else {
                           $ch->();
                        }
                     };
                  } else {
                     $grp->result (-1);
                     close $src_fh;
                     close $dst_fh;

                     aioreq $pri;
                     add $grp aio_unlink $dst;
                  }
               };
            } else {
               $grp->result (-1);
            }
         },

      } else {
         $grp->result (-1);
      }
   };

   $grp
}

=item aio_move $srcpath, $dstpath, $callback->($status)

Try to move the I<file> (directories not supported as either source or
destination) from C<$srcpath> to C<$dstpath> and call the callback with
a status of C<0> (ok) or C<-1> (error, see C<$!>).

This is a composite request that tries to rename(2) the file first; if
rename fails with C<EXDEV>, it copies the file with C<aio_copy> and, if
that is successful, unlinks the C<$srcpath>.

=cut

sub aio_move($$;$) {
   my ($src, $dst, $cb) = @_;

   my $pri = aioreq_pri;
   my $grp = aio_group $cb;

   aioreq_pri $pri;
   add $grp aio_rename $src, $dst, sub {
      if ($_[0] && $! == EXDEV) {
         aioreq_pri $pri;
         add $grp aio_copy $src, $dst, sub {



( run in 2.194 seconds using v1.01-cache-2.11-cpan-71847e10f99 )