Subject: | File processed again when not written to for 'resetafter' (default 600) seconds |
This is essentially the same issue as #107522.
When: File::Tail is used on a platform where 'stat' returns a useful number for ino and file is not written to for 'resetafter' seconds then entire file will be processed again..
Once the file was reset all is well and this no longer happens..
Attached patch is similar to #107522 (except that it also patches debugging file and adds a test case)
Example:
#!/usr/bin/perl
use File::Tail;
use File::Temp;
use IO::Handle;
my $fh = File::Temp->new();
my $fname = $fh->filename;
$fh->autoflush(1);
my $max_interval = $reset_after = 1;
my $file = File::Tail->new(
name => $fname,
resetafter => $reset_after,
interval => $max_interval,
maxinterval => $max_interval,
tail => -1,
);
print $fh "foo\n";
read_file();
sleep $reset_after;
read_file();
close $fh;
sub read_file {
my $r = $file->read();
chomp $r;
print "Data read: '$r'\n";
}
Output:
Data read: 'foo'
Data read: 'foo'
Expected output:
Data read: 'foo'
-- script waiting for data to be appended in file --
Subject: | 002-inode.patch |
diff --git a/Tail.pm b/Tail.pm
index 3ad3590..068ac74 100644
--- a/Tail.pm
+++ b/Tail.pm
@@ -404,6 +404,7 @@ sub reset_pointers {
} else { # This is the first time we are opening this file
$st=stat($newhandle);
$object->{handle}=$newhandle;
+ $object->{inode} = $st->ino;
$object->position;
$object->{lastread}=$st->mtime; # for better estimate on initial read
}
diff --git a/Tail.pm.debug b/Tail.pm.debug
index c79b4f3..683776b 100644
--- a/Tail.pm.debug
+++ b/Tail.pm.debug
@@ -415,6 +415,7 @@ sub reset_pointers {
$object->logit(" First opening of file");
$st=stat($newhandle);
$object->{handle}=$newhandle;
+ $object->{inode} = $st->ino;
$object->position;
$object->{lastread}=$st->mtime; # for better estimate on initial read
}
diff --git a/t/50reset.t b/t/50reset.t
new file mode 100644
index 0000000..db5ae59
--- /dev/null
+++ b/t/50reset.t
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use File::Tail;
+use File::Temp;
+use IO::Handle;
+use Test::More;
+
+my $fh = File::Temp->new();
+my $fname = $fh->filename;
+$fh->autoflush(1);
+
+my $max_interval = my $reset_after = 1;
+my $file = File::Tail->new(
+ name => $fname,
+ nowait => 1,
+ resetafter => $reset_after,
+ interval => $max_interval,
+ maxinterval => $max_interval,
+ tail => -1,
+);
+
+print $fh "foo\n";
+print $fh "bar\n";
+
+is(read_data(), "foo\n", "initial read (first line)");
+is(read_data(), "bar\n", "initial read (second line)");
+sleep $reset_after;
+
+is(read_data(), "", "read after $reset_after seconds");
+
+print $fh "baz\n";
+sleep $max_interval; # sleep again, ->read() only checks fh again
+ # after 'interval' seconds
+is(read_data(), "baz\n", "read after appending data");
+close $fh;
+
+done_testing();
+
+sub read_data {
+ my $r = $file->read();
+ if ($r eq "") {
+ # work-around for 'nowait'..
+ # see cpan #125810
+ $r = $file->read();
+ }
+ return $r;
+}