fix save_group and save_group_as

This commit is contained in:
Ward Wouts 2008-02-12 15:19:13 +00:00
parent 6e9300ee9b
commit e7f301c90d
2 changed files with 84 additions and 19 deletions

View file

@ -18,16 +18,19 @@
#
require "set/intspan"
#require "thread"
module News
class Newsrc
#@@save_lock = Mutex.new
def initialize(file=nil)
@newsrc = { "group" => Hash.new, "list" => Array.new }
if file
unless load(file)
print "Can't load #{file}\n"
puts "Can't load #{file}"
exit
end
end
@ -58,7 +61,7 @@ end
def parse(line)
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
print "Newsrc.parse: Bad newsrc line: #{line}\n"
puts "Newsrc.parse: Bad newsrc line: #{line}"
exit
end
@ -67,7 +70,7 @@ def parse(line)
articles = $3
unless Set::IntSpan.valid(articles)
print "Newsrc.parse: Bad article list: #{line}\n"
puts "Newsrc.parse: Bad article list: #{line}"
end
@ -85,49 +88,75 @@ def save
save_as(@newsrc["file"])
end
# this is not thread safe!
# this is not thread safe! (well, it should be now)
def save_as(file)
# @@save_lock.synchronize{
if FileTest.exists?("#{file}")
begin
File.rename(file, "#{file}.bak")
rescue
print "Can't rename #{file}, #{file}.bak: #{$!}\n"
puts "Can't rename #{file}, #{file}.bak: #{$!}"
exit
end
end
begin
newsrc = File.new(file, "w")
newsrc.flock(File::LOCK_EX)
rescue
print "Can't open #{file}: #{$!}\n"
puts "Can't open #{file}: #{$!}"
exit
end
@newsrc["file"] = file
@newsrc["list"].each{|group|
newsrc.print format(group)
}
newsrc.sync
newsrc.flock(File::LOCK_UN) # what's the right order here?
newsrc.close
# }
end
# Here 'group' is a group structure. It'd probably be much more useful if
# it could just be a group_name_; which it can now.
def save_group(group)
unless @newsrc.has_key?("file")
@newsrc["file"] = "#{$ENV['HOME']}/.newsrc"
end
save_as(@newsrc["file"], group)
if group.class.to_s == "String"
groupname = group.dup
@newsrc["list"].each{|g|
if g["name"] == groupname
group = g.dup
break
end
}
end
save_group_as(@newsrc["file"], group)
end
# this should be thread safe
# This should be thread safe, but may not be. It needs testing!
# If not, mutexes are needed.
def save_group_as(file, group)
# @@save_lock.synchronize{
p Time.now
p "copy file"
if FileTest.exists?("#{file}")
if ( ! File.copy(file, "#{file}.bak") )
print "Can't copy #{file} to #{file}.bak: #{$!}\n"
puts "Can't copy #{file} to #{file}.bak: #{$!}"
end
end
p Time.now
p "open & lock file"
begin
newsrc = File.new(file, "r+").flock(File::LOCK_EX)
newsrc = File.new(file, "r+")
newsrc.flock(File::LOCK_EX)
rescue
print "Can't open ${file}: #{$!}\n"
puts "Can't open ${file}: #{$!}"
exit
end
p Time.now
p "opened & locked"
# read file
lines = newsrc.readlines
@ -137,23 +166,46 @@ def save_group_as(file, group)
# write read stuff & replace group
lines.each{|line|
if line =~ /^#{group}(:|!)/
newsrc.print line
else
# same parsing as the parse method uses
unless line =~ /^([^!:]+)([!:])\s(.*)$/x
puts "Newsrc.parse: Bad newsrc line: #{line}"
# restore backup on failure, it'll contain the flaw too, but it'll
# be complete
if ( ! File.copy("#{file}.bak", file) )
puts "Can't copy #{file}.bak to #{file}: #{$!}"
end
exit
end
linegroup = $1
if linegroup == group["name"]
newsrc.print format(group)
else
newsrc.print line
end
}
p Time.now
p "truncate, sync, unlock & close file"
# sometimes the file grows and then shrinks
# this is because a 'read' line van become shorter when more
# articles have been read (1,3,5 vs 1-5)
# when this happens the file needs to be truncated
pos = newsrc.pos
newsrc.truncate(pos)
newsrc.sync
newsrc.flock(File::LOCK_UN) # what's the right order here?
newsrc.close
p Time.now
p "garbage collect"
p Time.now
GC.start
# }
end
def format(group)
name = group["name"]
sub = group["subscribed"] ? ':' : '!'
articles = group["articles"].run_list
#space = articles ? ' ' : ''
#return "#{name}#{sub}#{space}#{articles}\n"
return "#{name}#{sub} #{articles}\n"
end
@ -274,7 +326,6 @@ def number(group, offset)
@newsrc["list"].push(upper)
end
def del_group(name)
if @newsrc["group"].has_key?(name)
group = @newsrc["group"][name]
@ -306,7 +357,7 @@ def mark(name, article, options = {"where" => ""})
unless @newsrc["group"].has_key?(name)
add_group(name, options)
end
@newsrc["group"][name]["articles"].insert(article)
@newsrc["group"][name]["articles"].insert!(article)
end
def mark_list(name, list, options = {"where" => ""})

View file

@ -737,17 +737,20 @@ def main
_create_group_dir(group)
subjcount = 0
for subj in @articles.get_group_subjects.sort{|a, b| ward_sort(a, b)}
puts "#{subj}" if Debuglevel > 2
poster = @articles.get_group_poster(subj)
# explicitly mark as read
if @config[group].has_key?("-MR") and subj =~ /#{@config[group]["-MR"]}/
puts "Marking '#{subj}' as read"
subjcount += 1
_mark_read(subj)
# get the juicy bits
elsif @config[group].has_key?("-MRF") and poster =~ /#{@config[group]["-MRF"]}/
puts "Marking poster '#{poster}' as read (subj: '#{subj}')"
subjcount += 1
_mark_read(subj)
# get the juicy bits
elsif !(@config[group].has_key?("-X") and subj =~ /#{@config[group]["-X"]}/) and
subj =~ /#{@config[group]["-I"]}/
puts "Match: #{subj}" if Debuglevel > 0
@ -757,8 +760,19 @@ def main
puts "Poster match: #{poster}" if Debuglevel > 0
_get_article(subj, group)
else
subjcount += 1
_mark_remaining(subj, group)
end
# prevent haveing to start all over in case of a crash
# the number of subjects on which to sync should be balanced
# between the time it takes to sync and the time it takes to read them
# this is just an initial guess
# the counter is only used for the mark read stuff, as the get article
# stuff saves the newsrc anyway
if subjcount >= 150
_save_newsrc(group)
subjcount = 0
end
end
_wait_for_threads