Archive of RubyForge sup-devel mailing list
 help / color / mirror / Atom feed
From: "Edward Z. Yang" <ezyang@MIT.EDU>
To: sup-devel@rubyforge.org
Subject: [sup-devel] [PATCH] Inotify support for Maildirs. (FIRST DRAFT)
Date: Mon,  3 Sep 2012 00:59:31 -0400	[thread overview]
Message-ID: <1346648371-12305-1-git-send-email-ezyang@mit.edu> (raw)
In-Reply-To: <1345564795-sup-3898@alvh.no-ip.org>

From: "Edward Z. Yang" <ezyang@mit.edu>

Signed-off-by: Edward Z. Yang <ezyang@mit.edu>
---
 lib/sup/maildir.rb | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 lib/sup/poll.rb    | 33 ++++++++++++++++++++++++++-------
 lib/sup/source.rb  |  4 ++++
 3 files changed, 80 insertions(+), 9 deletions(-)

diff --git a/lib/sup/maildir.rb b/lib/sup/maildir.rb
index 2a91f05..743156d 100644
--- a/lib/sup/maildir.rb
+++ b/lib/sup/maildir.rb
@@ -1,5 +1,6 @@
 require 'uri'
 require 'set'
+require 'inotify'
 
 module Redwood
 
@@ -184,6 +185,45 @@ class Maildir < Source
     nil
   end
 
+  def continuous_poll poll_mutex
+    i = Inotify.new
+    watches = {}
+    @ctimes.each do |d,prev_ctime|
+      subdir = File.join @dir, d
+      wd = i.add_watch(subdir, Inotify::CREATE | Inotify::DELETE | Inotify::MOVE)
+      watches[wd] = d
+    end
+    i.each_event do |ev|
+      poll_mutex.synchronize do
+        @mutex.synchronize do
+          begin
+            ::Thread.current[@dir] = true
+            id = File.join watches[ev.wd], ev.name
+            # check if inotify is stale
+            # since we have @mutex, there is no race (except for
+            # an external program fucking us over)
+            next unless File.exists? File.join(@dir, id)
+            x = Enumerator.new(Index.instance, :each_source_info, self.id, "#{id}").to_a
+            if ev.mask & Inotify::CREATE or ev.mask & Inotify::MOVE_TO
+              next unless x.empty?
+              yield :add,
+                :info => id,
+                :labels => @labels + maildir_labels(id) + [:inbox],
+                :progress => 0
+            elsif ev.mask & Inotify::DELETE or ev.mask & Inotify::MOVE_FROM
+              next unless !x.empty?
+              yield :delete,
+                :info => id,
+                :progress => 0
+            end
+          ensure
+            ::Thread.current[@dir] = nil
+          end
+        end
+      end
+    end
+  end
+
   def labels? id
     maildir_labels id
   end
@@ -248,7 +288,16 @@ private
   end
 
   def maildir_move_file orig_path, new_source_id, flags
-    @mutex.synchronize do
+    if ::Thread.current[@dir]
+      _maildir_move_file orig_path, new_source_id, flags
+    else
+      @mutex.synchronize do
+        _maildir_move_file orig_path, new_source_id, flags
+      end
+    end
+  end
+
+  def _maildir_move_file orig_path, new_source_id, flags
       new_base = (flags.include?("S")) ? "cur" : "new"
       md_base, md_ver, md_flags = maildir_data orig_path
 
@@ -292,7 +341,6 @@ private
       end
 
       [new_source, new_loc]
-    end
   end
 end
 
diff --git a/lib/sup/poll.rb b/lib/sup/poll.rb
index dbd351f..51e0afa 100644
--- a/lib/sup/poll.rb
+++ b/lib/sup/poll.rb
@@ -94,11 +94,27 @@ EOS
         poll if @last_poll.nil? || (Time.now - @last_poll) >= @delay
       end
     end
+    # XXX dup dup
+    SourceManager.usual_sources.each do |source|
+      Redwood::reporting_thread("inotify poll for #{source}") do
+        source.continuous_poll @mutex do |sym, args|
+          poll_handler source, sym, args
+        end
+      end
+    end
+    SourceManager.unusual_sources.each do |source|
+      Redwood::reporting_thread("inotify poll for #{source}") do
+        source.continuous_poll @mutex do |sym, args|
+          poll_handler source, sym, args
+        end
+      end
+    end
   end
 
   def stop
     @thread.kill if @thread
     @thread = nil
+    # handle inotify polls
   end
 
   def do_poll
@@ -172,7 +188,16 @@ EOS
   ## from the index after being yielded.
   def poll_from source, opts={}
     begin
-      source.poll do |sym, args|
+      source.poll do |sym,args|
+        poll_handler source, sym, args
+      end
+      source.go_idle
+    rescue SourceError => e
+      warn "problem getting messages from #{source}: #{e.message}"
+    end
+  end
+
+  def poll_handler source, sym, args
         case sym
         when :add
           m = Message.build_from_source source, args[:info]
@@ -224,12 +249,6 @@ EOS
             UpdateManager.relay self, :updated, m
           end
         end
-      end
-
-      source.go_idle
-    rescue SourceError => e
-      warn "problem getting messages from #{source}: #{e.message}"
-    end
   end
 
   def handle_idle_update sender, idle_since; @should_clear_running_totals = false; end
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
index 06b6e6b..073a10a 100644
--- a/lib/sup/source.rb
+++ b/lib/sup/source.rb
@@ -102,6 +102,10 @@ class Source
     unimplemented
   end
 
+  ## Like poll, but never returns (it is continuous, and uses something
+  ## like inotify. Will always be run in another thread.)
+  def continuous_poll poll_mutex; [] end
+
   def valid? info
     true
   end
-- 
1.7.11.3

_______________________________________________
Sup-devel mailing list
Sup-devel@rubyforge.org
http://rubyforge.org/mailman/listinfo/sup-devel


  reply	other threads:[~2012-09-03  5:00 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-21 15:17 [sup-devel] inotify support for Maildir mailboxes Edward Z. Yang
2012-08-21 16:00 ` Alvaro Herrera
2012-09-03  4:59   ` Edward Z. Yang [this message]
2012-09-03  5:00     ` [sup-devel] [PATCH] Inotify support for Maildirs. (FIRST DRAFT) Edward Z. Yang
2012-09-03 16:02       ` Alvaro Herrera
2012-09-03 16:07         ` Alvaro Herrera
2012-09-03 16:10           ` ezyang
2012-09-03 18:09             ` Edward Z. Yang
2012-09-03 18:29               ` Edward Z. Yang
2012-09-03 18:42                 ` Alvaro Herrera
2012-09-03 18:49                   ` Edward Z. Yang
2012-09-03 19:27                   ` Edward Z. Yang
2012-09-03 23:31               ` Edward Z. Yang
2012-09-04 16:06                 ` Edward Z. Yang
2012-09-04 18:09                   ` Alvaro Herrera

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1346648371-12305-1-git-send-email-ezyang@mit.edu \
    --to=ezyang@mit.edu \
    --cc=sup-devel@rubyforge.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox