Subject: bug#18958: 25.0.50; auto-revert-mode reacts slowly even if using an event-driven backend

From: Dima Kogan <[email-masked]>
Date: Wed, 05 Nov 2014 11:01:12 -0800

This is a tracker entry for a report and patch in an emacs-devel mailing
list thread:

 http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00727.html

The issue is that auto-revert-mode reacts to modifications on a timer,
even if its backend is event-driven. There is a prototype patch in that
thread, attached here also.

On Linux, the two available backends have issues, so this patch wouldn't
be completely effective until those are resolved.

The gfile backend has a problem where emacs isn't using glib correctly,
and the gfile backend itself, in turn, adds artificial delays in how it
deals with inotify. Those are discussed (and partly patched) here:

 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18861

The inotify backend has an issue where it doesn't deal with more than
one monitored file in a directory correctly:

 http://debbugs.gnu.org/cgi/bugreport.cgi?bug=18880

>From 567d8469dfb143786890c65de58bf2ce887e9ebd Mon Sep 17 00:00:00 2001
From: Dima Kogan <[email-masked]>
Date: Fri, 24 Oct 2014 19:44:43 -0700
Subject: [PATCH] auto-revert-mode can now revert immediately in response to a
 change event

If we have file notifications, we want to update the auto-revert buffers
immediately when a notification occurs. Since file updates can happen very
often, we want to skip some revert operations so that we don't spend all our
time reverting the buffer.

We do this by reverting immediately in response to the first in a flurry of
notifications. We suppress subsequent notifications until the next time
`auto-revert-buffers' is called (this happens on a timer with a period set by
`auto-revert-interval').
---
 lisp/autorevert.el | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/lisp/autorevert.el b/lisp/autorevert.el
index f1074e2..7de6ec1 100644
--- a/lisp/autorevert.el
+++ b/lisp/autorevert.el
@@ -531,6 +531,34 @@ will use an up-to-date value of `auto-revert-interval'"
       ;; Fallback to file checks.
       (set (make-local-variable 'auto-revert-use-notify) nil))))
 
+
+
+;; If we have file notifications, we want to update the auto-revert buffers
+;; immediately when a notification occurs. Since file updates can happen very
+;; often, we want to skip some revert operations so that we don't spend all our
+;; time reverting the buffer.
+;;
+;; We do this by reverting immediately in response to the first in a flurry of
+;; notifications. We suppress subsequent notifications until the next time
+;; `auto-revert-buffers' is called (this happens on a timer with a period set by
+;; `auto-revert-interval').
+(defvar auto-revert-buffers-counter 1
+  "Incremented each time `auto-revert-buffers' is called")
+(defvar auto-revert-buffers-counter-lockedout 0
+  "Buffer-local value to indicate whether we should immediately
+update the buffer on a notification event or not. If
+
+  (= auto-revert-buffers-counter-lockedout
+     auto-revert-buffers-counter)
+
+then the updates are locked out, and we wait until the next call
+of `auto-revert-buffers' to revert the buffer. If no lockout is
+present, then we revert immediately and set the lockout, so that
+no more reverts are possible until the next call of
+`auto-revert-buffers'")
+(make-variable-buffer-local 'auto-revert-buffers-counter-lockedout)
+
+
 (defun auto-revert-notify-handler (event)
   "Handle an EVENT returned from file notification."
   (with-demoted-errors
@@ -566,6 +594,14 @@ will use an up-to-date value of `auto-revert-interval'"
                                 (file-name-nondirectory buffer-file-name)))))
                 ;; Mark buffer modified.
                 (setq auto-revert-notify-modified-p t)
+
+                ;; Revert the buffer now if we're not locked out
+                (when (/= auto-revert-buffers-counter-lockedout
+                          auto-revert-buffers-counter)
+                  (auto-revert-handler)
+                  (setq auto-revert-buffers-counter-lockedout
+                        auto-revert-buffers-counter))
+
                 ;; No need to check other buffers.
                 (cl-return)))))))))
 
@@ -686,6 +722,10 @@ are checked first the next time this function is called.
 This function is also responsible for removing buffers no longer in
 Auto-Revert mode from `auto-revert-buffer-list', and for canceling
 the timer when no buffers need to be checked."
+
+  (setq auto-revert-buffers-counter
+        (1+ auto-revert-buffers-counter))
+
   (save-match-data
     (let ((bufs (if global-auto-revert-mode
 		    (buffer-list)
-- 
2.0.0