Show More
Commit Description:
added solution submission with grading
Commit Description:
added solution submission with grading
References:
File last commit:
Show/Diff file:
Action:
judge/scripts/lib/dir_init.rb
| 126 lines
| 3.1 KiB
| text/x-ruby
| RubyLexer
|
|
r179 | 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. | ||||
|
r180 | # | ||
# 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. | ||||
|
r179 | |||
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 | ||||