1package AnyEvent::Filesys::Notify::Role::KQueue; 2 3# ABSTRACT: Use IO::KQueue to watch for changed files 4 5use Moo::Role; 6use MooX::late; 7use namespace::autoclean; 8use AnyEvent; 9use IO::KQueue; 10use Carp; 11 12our $VERSION = '1.23'; 13 14# Arbitrary limit on open filehandles before issuing a warning 15our $WARN_FILEHANDLE_LIMIT = 50; 16 17sub _init { 18 my $self = shift; 19 20 my $kqueue = IO::KQueue->new() 21 or croak "Unable to create new IO::KQueue object"; 22 $self->_fs_monitor($kqueue); 23 24 # Need to add all the subdirs to the watch list, this will catch 25 # modifications to files too. 26 my $old_fs = $self->_old_fs; 27 my @paths = keys %$old_fs; 28 29 # Add each file and each directory to a hash of path => fh 30 my $fhs = {}; 31 for my $path (@paths) { 32 my $fh = $self->_watch($path); 33 $fhs->{$path} = $fh if defined $fh; 34 } 35 36 # Now use AE to watch the KQueue 37 my $w; 38 $w = AE::io $$kqueue, 0, sub { 39 if ( my @events = $kqueue->kevent ) { 40 $self->_process_events(@events); 41 } 42 }; 43 $self->_watcher( { fhs => $fhs, w => $w } ); 44 45 $self->_check_filehandle_count; 46 return 1; 47} 48 49# Need to add newly created items (directories and files) or remove deleted 50# items. This isn't going to be perfect. If the path is not canonical then we 51# won't deleted it. This is done after filtering. So entire dirs can be 52# ignored efficiently. 53sub _post_process_events { 54 my ( $self, @events ) = @_; 55 56 for my $event (@events) { 57 if ( $event->is_created ) { 58 my $fh = $self->_watch( $event->path ); 59 $self->_watcher->{fhs}->{ $event->path } = $fh if defined $fh; 60 } elsif ( $event->is_deleted ) { 61 delete $self->_watcher->{fhs}->{ $event->path }; 62 } 63 } 64 65 $self->_check_filehandle_count; 66 return; 67} 68 69sub _watch { 70 my ( $self, $path ) = @_; 71 72 open my $fh, '<', $path or do { 73 warn 74 "KQueue requires a filehandle for each watched file and directory.\n" 75 . "You have exceeded the number of filehandles permitted by the OS.\n" 76 if $! =~ /^Too many open files/; 77 return if $! =~ /no such file or directory/i; 78 croak "Can't open file ($path): $!"; 79 }; 80 81 $self->_fs_monitor->EV_SET( 82 fileno($fh), 83 EVFILT_VNODE, 84 EV_ADD | EV_ENABLE | EV_CLEAR, 85 NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | 86 NOTE_RENAME | NOTE_REVOKE, 87 ); 88 89 return $fh; 90} 91 92sub _check_filehandle_count { 93 my ($self) = @_; 94 95 my $count = $self->_watcher_count; 96 carp "KQueue requires a filehandle for each watched file and directory.\n" 97 . "You currently have $count filehandles for this AnyEvent::Filesys::Notify object.\n" 98 . "The use of the KQueue backend is not recommended." 99 if $count > $WARN_FILEHANDLE_LIMIT; 100 101 return $count; 102} 103 104sub _watcher_count { 105 my ($self) = @_; 106 my $fhs = $self->_watcher->{fhs}; 107 return scalar keys %$fhs; 108} 109 1101; 111 112__END__ 113 114=pod 115 116=head1 NAME 117 118AnyEvent::Filesys::Notify::Role::KQueue - Use IO::KQueue to watch for changed files 119 120=head1 VERSION 121 122version 1.23 123 124=head1 AUTHOR 125 126Mark Grimes, E<lt>mgrimes@cpan.orgE<gt> 127 128=head1 CONTRIBUTORS 129 130=over 4 131 132=item * 133 134Gasol Wu E<lt>gasol.wu@gmail.comE<gt> who contributed the BSD support for IO::KQueue 135 136=item * 137 138Dave Hayes E<lt>dave@jetcafe.orgE<gt> 139 140=item * 141 142Carsten Wolff E<lt>carsten@wolffcarsten.deE<gt> 143 144=item * 145 146Ettore Di Giacinto (@mudler) 147 148=item * 149 150Martin Barth (@ufobat) 151 152=back 153 154=head1 SOURCE 155 156Source repository is at L<https://github.com/mvgrimes/AnyEvent-Filesys-Notify>. 157 158=head1 BUGS 159 160Please report any bugs or feature requests on the bugtracker website L<http://github.com/mvgrimes/AnyEvent-Filesys-Notify/issues> 161 162When submitting a bug or request, please include a test-file or a 163patch to an existing test-file that illustrates the bug or desired 164feature. 165 166=head1 COPYRIGHT AND LICENSE 167 168This software is copyright (c) 2017 by Mark Grimes, E<lt>mgrimes@cpan.orgE<gt>. 169 170This is free software; you can redistribute it and/or modify it under 171the same terms as the Perl 5 programming language system itself. 172 173=cut 174