[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: inotify back end for tail -f on linux
From: |
Giuseppe Scrivano |
Subject: |
Re: inotify back end for tail -f on linux |
Date: |
Sat, 30 May 2009 13:50:42 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.0.94 (gnu/linux) |
Hi Jim,
Jim Meyering <address@hidden> writes:
> Thanks for the suggestion.
> Yes, this has been discussed, e.g., in
>
> http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/15031/focus=15052
>
> I like the idea and outlined how I'd like to see this functionality
> make it's way into the coreutils.
I read this discussion but looking at the tail source code I didn't see
any difficulty to use inotify.
These are some tests results:
test -e /tmp/files || mkdir /tmp/files;
for i in $(seq 2000); do touch /tmp/files/$i; done
my version:
./timeout -sINT 30s env time ./tail -f /tmp/files/*
0.02user 0.09system 0:30.00elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+232minor)pagefaults 0swaps
system version:
./timeout -sINT 30s env time tail -f /tmp/files/*
0.05user 0.16system 0:29.99elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+236minor)pagefaults 0swaps
I am sure running the test for a longer time would give better
results. The initial time using inotify is higher as there is need to
create watch descriptors and an index I use for access to the File_spec
in costant time.
What do you think of the attached patch?
Cheers,
Giuseppe
>From aa815abdd3cbf2ad15d769a1f4cb6100e3a975e5 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <address@hidden>
Date: Sat, 30 May 2009 13:31:58 +0200
Subject: [PATCH] tail: Use inotify if it is available.
* NEWS: Document the new feature
* configure.ac: Check if inotify is present.
* src/tail.c (main): Use the tail_forever inotify version if it
is possible.
(tail_forever_inotify): Added new function.
---
NEWS | 2 +
configure.ac | 2 +
src/tail.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 29b09a0..c5a2ef5 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ GNU coreutils NEWS -*-
outline -*-
sort accepts a new option, --human-numeric-sort (-h): sort numbers
while honoring human readable suffixes like KiB and MB etc.
+ tail uses inotify if it is present.
+
* Noteworthy changes in release 7.4 (2009-05-07) [stable]
diff --git a/configure.ac b/configure.ac
index 4eb640e..a63ac0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -410,6 +410,8 @@ AM_GNU_GETTEXT_VERSION([0.15])
# For a test of uniq: it uses the $LOCALE_FR envvar.
gt_LOCALE_FR
+AC_CHECK_FUNCS([inotify_init], [AC_DEFINE([HAVE_INOTIFY], [1], [Check for
libinotify])])
+
AC_CONFIG_FILES(
Makefile
doc/Makefile
diff --git a/src/tail.c b/src/tail.c
index fe34600..bb0950e 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -1,5 +1,5 @@
/* tail -- output the last part of file(s)
- Copyright (C) 1989, 90, 91, 1995-2006, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90, 91, 1995-2006, 2008, 2009 Free Software Foundation,
Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,6 +45,10 @@
#include "xstrtol.h"
#include "xstrtod.h"
+#ifdef HAVE_INOTIFY
+#include <sys/inotify.h>
+#endif
+
/* The official name of this program (e.g., no `g' prefix). */
#define PROGRAM_NAME "tail"
@@ -1116,6 +1120,93 @@ tail_forever (struct File_spec *f, int nfiles, double
sleep_interval)
}
}
+#ifdef HAVE_INOTIFY
+/* Tail NFILES files forever, or until killed.
+ Check modifications using the inotify events system. */
+static void
+tail_forever_inotify (int wd, struct File_spec *f, int nfiles)
+{
+ /* Create an index to access File_spec by its watch descriptor
+ * in costant time. */
+ struct File_spec **wd_index;
+ int i;
+ int *watch_fd = xmalloc (sizeof (int) * nfiles);
+ int min_wd = -1;
+ int max_wd = -1;
+ int watched = 0;
+ size_t last;
+
+ for (i = 0; i < nfiles; i++)
+ {
+ watch_fd[i] = -1;
+
+ if (!f[i].ignore)
+ {
+ watch_fd[i] = inotify_add_watch (wd, f[i].name,
+ IN_MODIFY);
+
+ if (watch_fd[i] < 0)
+ {
+ error (0, errno, _("cannot watch %s"), quote (f[i].name));
+ continue;
+ }
+
+ watched++;
+
+ if (watch_fd[i] > max_wd || max_wd < 0)
+ max_wd = watch_fd[i];
+
+ if (watch_fd[i] < min_wd || min_wd < 0)
+ min_wd = watch_fd[i];
+ }
+ }
+
+ if (!watched)
+ return;
+
+ wd_index = xmalloc (sizeof (struct File_spec**) * (max_wd - min_wd + 1));
+
+ for (i = 0; i < nfiles; i++)
+ if (watch_fd[i] > 0)
+ wd_index[watch_fd[i] - min_wd] = &(f[i]);
+
+ free (watch_fd);
+
+ last = max_wd + 1;
+
+ while (1)
+ {
+ size_t len;
+ struct inotify_event ev;
+ char const *name;
+ struct File_spec *fspec;
+ uintmax_t bytes_read;
+
+ len = read (wd, &ev, sizeof (struct inotify_event));
+ if (!len && errno == EINTR)
+ continue;
+
+ if (!len)
+ error (EXIT_FAILURE, errno, _("error reading inotify event"));
+
+ fspec = wd_index [ev.wd - min_wd];
+
+ name = pretty_name (fspec);
+
+ if (ev.wd != last)
+ {
+ if (print_headers)
+ write_header (name);
+ last = ev.wd;
+ }
+
+ bytes_read = dump_remainder (name, fspec->fd, COPY_TO_EOF);
+ fspec->size += bytes_read;
+ }
+
+}
+#endif
+
/* Output the last N_BYTES bytes of file FILENAME open for reading in FD.
Return true if successful. */
@@ -1690,7 +1781,15 @@ main (int argc, char **argv)
ok &= tail_file (&F[i], n_units);
if (forever)
- tail_forever (F, n_files, sleep_interval);
+ {
+#ifdef HAVE_INOTIFY
+ int wd = inotify_init ();
+
+ if (wd > 0)
+ tail_forever_inotify (wd, F, n_files);
+#endif
+ tail_forever (F, n_files, sleep_interval);
+ }
if (have_read_stdin && close (STDIN_FILENO) < 0)
error (EXIT_FAILURE, errno, "-");
--
1.6.3.1
- Re: inotify back end for tail -f on linux,
Giuseppe Scrivano <=