]> git.cworth.org Git - sup/commitdiff
synchronize access to sources
authorWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 6 Nov 2008 20:31:40 +0000 (12:31 -0800)
committerWilliam Morgan <wmorgan-sup@masanjin.net>
Thu, 6 Nov 2008 20:51:22 +0000 (12:51 -0800)
lib/sup/imap.rb
lib/sup/index.rb

index 1d369767c43106fdb19737244f172adbba8f644c..52703364b859bdc0375193e7508660fbac92fc90 100644 (file)
@@ -5,6 +5,9 @@ require 'time'
 require 'rmail'
 require 'cgi'
 
+## TODO: remove synchronized method protector calls; use a Monitor instead
+## (ruby's reentrant mutex)
+
 ## fucking imap fucking sucks. what the FUCK kind of committee of dunces
 ## designed this shit.
 ##
@@ -15,7 +18,7 @@ require 'cgi'
 ## restriction. it can change any time you log in. it can change EVERY
 ## time you log in. of course the imap spec "strongly recommends" that it
 ## never change, but there's nothing to stop people from just setting it
-## to the current timestamp, and in fact that's exactly what the one imap
+## to the current timestamp, and in fact that's EXACTLY what the one imap
 ## server i have at my disposal does. thus the so-called uids are
 ## absolutely useless and imap provides no cross-session way of uniquely
 ## identifying a message. but thanks for the "strong recommendation",
index 235a18cb0d7993c306d58f0b0e6168ca4b6ec7c5..defc3edcf098df01a5ee32433c30e6eb83999b41 100644 (file)
@@ -2,6 +2,8 @@
 
 require 'fileutils'
 require 'ferret'
+require 'fastthread'
+
 begin
   require 'chronic'
   $have_chronic = true
@@ -29,6 +31,7 @@ class Index
     @dir = dir
     @sources = {}
     @sources_dirty = false
+    @source_mutex = Monitor.new
 
     wsa = Ferret::Analysis::WhiteSpaceAnalyzer.new false
     sa = Ferret::Analysis::StandardAnalyzer.new [], true
@@ -122,17 +125,19 @@ EOS
   end
 
   def add_source source
-    raise "duplicate source!" if @sources.include? source
-    @sources_dirty = true
-    max = @sources.max_of { |id, s| s.is_a?(DraftLoader) || s.is_a?(SentLoader) ? 0 : id }
-    source.id ||= (max || 0) + 1
-    ##source.id += 1 while @sources.member? source.id
-    @sources[source.id] = source
+    @source_mutex.synchronize do
+      raise "duplicate source!" if @sources.include? source
+      @sources_dirty = true
+      max = @sources.max_of { |id, s| s.is_a?(DraftLoader) || s.is_a?(SentLoader) ? 0 : id }
+      source.id ||= (max || 0) + 1
+      ##source.id += 1 while @sources.member? source.id
+      @sources[source.id] = source
+    end
   end
 
   def sources
     ## favour the inbox by listing non-archived sources first
-    @sources.values.sort_by { |s| s.id }.partition { |s| !s.archived? }.flatten
+    @source_mutex.synchronize { @sources.values }.sort_by { |s| s.id }.partition { |s| !s.archived? }.flatten
   end
 
   def source_for uri; sources.find { |s| s.is_source_for? uri }; end
@@ -364,7 +369,7 @@ EOS
   ## builds a message object from a ferret result
   def build_message docid
     doc = @index[docid]
-    source = @sources[doc[:source_id].to_i]
+    source = @source_mutex.synchronize { @sources[doc[:source_id].to_i] }
     #puts "building message #{doc[:message_id]} (#{source}##{doc[:source_info]})"
     raise "invalid source #{doc[:source_id]}" unless source
 
@@ -426,8 +431,10 @@ EOS
 
   def load_sources fn=Redwood::SOURCE_FN
     source_array = (Redwood::load_yaml_obj(fn) || []).map { |o| Recoverable.new o }
-    @sources = Hash[*(source_array).map { |s| [s.id, s] }.flatten]
-    @sources_dirty = false
+    @source_mutex.synchronize do
+      @sources = Hash[*(source_array).map { |s| [s.id, s] }.flatten]
+      @sources_dirty = false
+    end
   end
 
   def has_any_from_source_with_label? source, label
@@ -555,16 +562,18 @@ protected
   end
 
   def save_sources fn=Redwood::SOURCE_FN
-    if @sources_dirty || @sources.any? { |id, s| s.dirty? }
-      bakfn = fn + ".bak"
-      if File.exists? fn
+    @source_mutex.synchronize do
+      if @sources_dirty || @sources.any? { |id, s| s.dirty? }
+        bakfn = fn + ".bak"
+        if File.exists? fn
+          File.chmod 0600, fn
+          FileUtils.mv fn, bakfn, :force => true unless File.exists?(bakfn) && File.size(fn) == 0
+        end
+        Redwood::save_yaml_obj sources.sort_by { |s| s.id.to_i }, fn, true
         File.chmod 0600, fn
-        FileUtils.mv fn, bakfn, :force => true unless File.exists?(bakfn) && File.size(fn) == 0
       end
-      Redwood::save_yaml_obj sources.sort_by { |s| s.id.to_i }, fn, true
-      File.chmod 0600, fn
+      @sources_dirty = false
     end
-    @sources_dirty = false
   end
 end