[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[sup-devel] [PATCH] Inotify support for Maildirs. (FIRST DRAFT)



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