From 95e1f7e3fb05db7f313c49e82040eb6b626fb10d Mon Sep 17 00:00:00 2001 From: William Morgan Date: Thu, 6 Nov 2008 12:31:40 -0800 Subject: [PATCH] synchronize access to sources --- lib/sup/imap.rb | 5 ++++- lib/sup/index.rb | 43 ++++++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/sup/imap.rb b/lib/sup/imap.rb index 1d36976..5270336 100644 --- a/lib/sup/imap.rb +++ b/lib/sup/imap.rb @@ -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", diff --git a/lib/sup/index.rb b/lib/sup/index.rb index 235a18c..defc3ed 100644 --- a/lib/sup/index.rb +++ b/lib/sup/index.rb @@ -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 -- 2.45.2