Show More
Commit Description:
copy working trunk (r383, before major changes to combine judge and to support grader message queue) to trunk...
Commit Description:
copy working trunk (r383, before major changes to combine judge and to support grader message queue) to trunk git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@396 6386c4cd-e34a-4fa8-8920-d93eb39b512e
References:
File last commit:
Show/Diff file:
Action:
judge/scripts/lib/dir_init.rb | 126 lines | 3.1 KiB | text/x-ruby | RubyLexer |
require 'ftools'
# DirInit::Manager handles directory initialization and clean-up when
# there are many concurrent processes that wants to modify the
# directory in the same way.
#
# An example usage is when each process wants to copy some temporary
# files to the directory and delete these files after finishing its
# job. Problems may occur when the first process delete the files
# while the second process is still using the files.
#
# This library maintain a reference counter on the processes using the
# directory. It locks the dir to manage critical section when
# updating the reference counter.
#
# Example usage:
#
# dman = DirInit::Manager.new("mydir")
#
# dman.setup do
# # do some initialization
# end
#
# #... do anything you want
#
# dman.teardown do
# # clean up
# end
#
# DirInit::Manager ensures that the block passed to <tt>setup</tt>
# only runs once by the first process in the concurrent dir usage and
# block passed to <tt>teardown</tt> runs once by the last process in
# that concurrent activities leaving that dir.
module DirInit
class Manager
def initialize(dir_name, usage_filename='.usage_counter')
@dir_name = dir_name
@usage_filename = usage_filename
end
# Check if someone has initialized the dir. If not, call block.
def setup # :yields: block
dir = File.new(@dir_name)
dir.flock(File::LOCK_EX)
begin
counter_filename = get_counter_filename
if File.exist? counter_filename
# someone is here
f = File.new(counter_filename,"r+")
counter = f.read.to_i
f.seek(0)
f.write("#{counter+1}\n")
f.close
else
# i'm the first, create the counter file
counter = 0
f = File.new(counter_filename,"w")
f.write("1\n")
f.close
end
# if no one is here
if counter == 0
if block_given?
yield
end
end
rescue
raise
ensure
# make sure it unlock the directory
dir.flock(File::LOCK_UN)
end
end
# Check if I am the last one using the dir. If true, call block.
def teardown
dir = File.new(@dir_name)
dir.flock(File::LOCK_EX)
begin
counter_filename = get_counter_filename
if File.exist? counter_filename
# someone is here
f = File.new(counter_filename,"r+")
counter = f.read.to_i
f.seek(0)
f.write("#{counter-1}\n")
f.close
if counter == 1
# i'm the last one
File.delete(counter_filename)
if block_given?
yield
end
end
else
# This is BAD
raise "Error: reference count missing"
end
rescue
raise
ensure
# make sure it unlock the directory
dir.flock(File::LOCK_UN)
end
end
protected
def get_counter_filename
return File.join(@dir_name,@usage_filename)
end
end
end