pktrain has asked for the wisdom of the Perl Monks concerning the following question:

Dearest Monks,

I made a post a while ago asking for some assistance with using the Linux::Inotify2 package. Specifically I wanted to know how I could use Inotify2 to watch a specified set of subdirectories for new files that have been (completely) created and perform some action on them.

The commands didn't seem to work the way I expected at first so I investigated exactly what signals are generated when a file is written to a directory using the following Perl script:

#!/usr/bin/perl -w use strict; use warnings; use diagnostics; use Linux::Inotify2; $|++; my $inotify = new Linux::Inotify2 or die "Unable to create new inotify + object: $!"; my $logfile = "/home/ldm/logs/pqinsert_check.log"; my @time = localtime; my $path = "/home/ldm/temp/"; my @site_array = ("ktst1", "ktst2"); my $site_cnt = 0; foreach my $site (@site_array) { my $path_site = $path . $site; $inotify->watch($path_site, IN_ALL_EVENTS, sub { my $event = shift; my $name = $event->fullname; open Wlog, ">>$logfile"; print Wlog "$name = IN_ACCESS\n" if $event->IN_ACCESS; print Wlog "$name = IN_MODIFY\n" if $event->IN_MODIFY; print Wlog "$name = IN_ATTRIB\n" if $event->IN_ATTRIB; print Wlog "$name = IN_CLOSE_WRITE\n" if $event->IN_CL +OSE_WRITE; print Wlog "$name = IN_CLOSE_NOWRITE\n" if $event->IN_ +CLOSE_NOWRITE; print Wlog "$name = IN_OPEN\n" if $event->IN_OPEN; print Wlog "$name = IN_MOVED_FROM\n" if $event->IN_MOV +ED_FROM; print Wlog "$name = IN_MOVED_TO\n" if $event->IN_MOVED +_TO; print Wlog "$name = IN_CREATE\n" if $event->IN_CREATE; print Wlog "$name = IN_DELETE\n" if $event->IN_DELETE; print Wlog "$name = IN_MOVE_SELF\n" if $event->IN_MOVE +_SELF; print Wlog "$name = IN_DELETE_SELF\n" if $event->IN_DE +LETE_SELF; close Wlog; }) or die "Watch creation failed: $!"; if (!($site_cnt)) { open Wlog, ">$logfile"; printf Wlog "%4d-%02d-%02d %02d:%02d:%02d\n", $time[5] ++1900, $time[4]+1, $time[3], $time[2], $time[1], $time[0]; } else { open Wlog, ">>$logfile"; } print Wlog "Watch established on: $path_site\n"; close Wlog; $site_cnt++; } 1 while $inotify->poll;

When I wrote (copied) a file (20080609-080008.cdf, ~1.9MB) into one of the test directories I set up to watch, I got the following interesting results:

2009-02-22 19:08:02 Watch established on: /home/ldm/temp/ktst1 Watch established on: /home/ldm/temp/ktst2 /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_CREATE /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_OPEN /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_MODIFY /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_CLOSE_WRITE /home/ldm/temp/ktst1/20080609-080008.cdf = IN_CREATE /home/ldm/temp/ktst1/20080609-080008.cdf.filepart = IN_DELETE /home/ldm/temp/ktst1/20080609-080008.cdf = IN_ATTRIB

So (on my machine running CentOS 5.2) there appears as though there is no IN_CLOSE signal generated when the complete target file is written. Apparently only the file metadata is changed sending the IN_ATTRIB signal at the end.

I had to change the Inotify2 watch from what I intuitively thought to be an IN_CLOSE signal to IN_ATTRIB to actually detect when the complete (without the .filepart extension as desired) file was written in the directory. This is very convenient because it is the only signal of this type generated during file creation eliminating the need to, say, discern between IN_CREATE signals generated by the target file and its file part.

I had never seen this before and wanted to share this finding with the community here to hopefully save someone some time and hassle I went through. I have this running now and it works great.

UPDATE:

I just ran this script on a machine running Ubuntu and the results were very different! On the Ubuntu machine when I copied a file (same operation as above) the signal list looks like this:

2009-02-28 01:43:24 Watch established on: /mnt/ldmdata/kdlh Watch established on: /mnt/ldmdata/kfsd Watch established on: /mnt/ldmdata/kmpx Watch established on: /mnt/ldmdata/kmvx Watch established on: /mnt/ldmdata/kwbc /mnt/ldmdata/karx/20090210-213015.cdf = IN_CREATE /mnt/ldmdata/karx/20090210-213015.cdf = IN_OPEN /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_MODIFY /mnt/ldmdata/karx/20090210-213015.cdf = IN_CLOSE_WRITE

So the bottom line here is there are different sequences of signals generated for a file write based on the flavor of Linux. This becomes especially important when using a package to monitor signals like Inotify2. Check your signals!

Replies are listed 'Best First'.
Re: Inotify2 findings
by zentara (Cardinal) on Feb 23, 2009 at 11:37 UTC
    and wanted to share this finding with the community here to hopefully save someone some time and hassle I went through.

    I, for one will thank you for sharing your script....it's always nice to have working example/solutions posted.


    I'm not really a human, but I play one on earth My Petition to the Great Cosmic Conciousness