Description:
locks dir based on temp file, does not copy dir when copying scripts, added proper rescue for ln_s
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r103:933325ce824a - - 4 files changed: 4 inserted, 3 deleted

@@ -1,76 +1,76
1 require 'ftools'
1 require 'ftools'
2
2
3 # DirInit::Manager handles directory initialization and clean-up when
3 # DirInit::Manager handles directory initialization and clean-up when
4 # there are many concurrent processes that wants to modify the
4 # there are many concurrent processes that wants to modify the
5 # directory in the same way.
5 # directory in the same way.
6 #
6 #
7 # An example usage is when each process wants to copy some temporary
7 # An example usage is when each process wants to copy some temporary
8 # files to the directory and delete these files after finishing its
8 # files to the directory and delete these files after finishing its
9 # job. Problems may occur when the first process delete the files
9 # job. Problems may occur when the first process delete the files
10 # while the second process is still using the files.
10 # while the second process is still using the files.
11 #
11 #
12 # This library maintain a reference counter on the processes using the
12 # This library maintain a reference counter on the processes using the
13 # directory. It locks the dir to manage critical section when
13 # directory. It locks the dir to manage critical section when
14 # updating the reference counter.
14 # updating the reference counter.
15
15
16 module DirInit
16 module DirInit
17
17
18 class Manager
18 class Manager
19
19
20 def initialize(dir_name, usage_filename='.usage_counter')
20 def initialize(dir_name, usage_filename='.usage_counter')
21 @dir_name = dir_name
21 @dir_name = dir_name
22 @usage_filename = usage_filename
22 @usage_filename = usage_filename
23 end
23 end
24
24
25 # Check if someone has initialized the dir. If not, call block.
25 # Check if someone has initialized the dir. If not, call block.
26
26
27 def setup # :yields: block
27 def setup # :yields: block
28 - dir = File.new(@dir_name)
28 + dir = File.new(@dir_name + '/lockfile',"w+")
29 dir.flock(File::LOCK_EX)
29 dir.flock(File::LOCK_EX)
30 begin
30 begin
31 counter_filename = get_counter_filename
31 counter_filename = get_counter_filename
32 if File.exist? counter_filename
32 if File.exist? counter_filename
33 # someone is here
33 # someone is here
34 f = File.new(counter_filename,"r+")
34 f = File.new(counter_filename,"r+")
35 counter = f.read.to_i
35 counter = f.read.to_i
36 f.seek(0)
36 f.seek(0)
37 f.write("#{counter+1}\n")
37 f.write("#{counter+1}\n")
38 f.close
38 f.close
39 else
39 else
40 # i'm the first, create the counter file
40 # i'm the first, create the counter file
41 counter = 0
41 counter = 0
42 f = File.new(counter_filename,"w")
42 f = File.new(counter_filename,"w")
43 f.write("1\n")
43 f.write("1\n")
44 f.close
44 f.close
45 end
45 end
46
46
47 # if no one is here
47 # if no one is here
48 if counter == 0
48 if counter == 0
49 if block_given?
49 if block_given?
50 yield
50 yield
51 end
51 end
52 end
52 end
53
53
54 rescue
54 rescue
55 raise
55 raise
56
56
57 ensure
57 ensure
58 # make sure it unlock the directory
58 # make sure it unlock the directory
59 dir.flock(File::LOCK_UN)
59 dir.flock(File::LOCK_UN)
60 dir.close
60 dir.close
61 end
61 end
62 end
62 end
63
63
64 # Check if I am the last one using the dir. If true, call block.
64 # Check if I am the last one using the dir. If true, call block.
65
65
66 def teardown
66 def teardown
67 dir = File.new(@dir_name)
67 dir = File.new(@dir_name)
68 dir.flock(File::LOCK_EX)
68 dir.flock(File::LOCK_EX)
69 begin
69 begin
70 counter_filename = get_counter_filename
70 counter_filename = get_counter_filename
71 if File.exist? counter_filename
71 if File.exist? counter_filename
72 # someone is here
72 # someone is here
73 f = File.new(counter_filename,"r+")
73 f = File.new(counter_filename,"r+")
74 counter = f.read.to_i
74 counter = f.read.to_i
75 f.seek(0)
75 f.seek(0)
76 f.write("#{counter-1}\n")
76 f.write("#{counter-1}\n")
@@ -91,96 +91,97
91 copy_log = load_copy_log(problem_home)
91 copy_log = load_copy_log(problem_home)
92 clear_copy_log(problem_home)
92 clear_copy_log(problem_home)
93 clear_script(copy_log,problem_home)
93 clear_script(copy_log,problem_home)
94 end
94 end
95
95
96 rescue RuntimeError => msg
96 rescue RuntimeError => msg
97 @reporter.report_error(submission, msg)
97 @reporter.report_error(submission, msg)
98
98
99 ensure
99 ensure
100 @room_maker.clean_up(submission)
100 @room_maker.clean_up(submission)
101 Dir.chdir(current_dir) # this is really important
101 Dir.chdir(current_dir) # this is really important
102 end
102 end
103 end
103 end
104
104
105 protected
105 protected
106
106
107 def talk(str)
107 def talk(str)
108 if @config.talkative
108 if @config.talkative
109 puts str
109 puts str
110 end
110 end
111 end
111 end
112
112
113 def call_judge(problem_home,language,grading_dir,fname)
113 def call_judge(problem_home,language,grading_dir,fname)
114 ENV['PROBLEM_HOME'] = problem_home
114 ENV['PROBLEM_HOME'] = problem_home
115
115
116 talk grading_dir
116 talk grading_dir
117 Dir.chdir grading_dir
117 Dir.chdir grading_dir
118 cmd = "#{problem_home}/script/judge #{language} #{fname}"
118 cmd = "#{problem_home}/script/judge #{language} #{fname}"
119 talk "CMD: #{cmd}"
119 talk "CMD: #{cmd}"
120 system(cmd)
120 system(cmd)
121 end
121 end
122
122
123 def get_std_script_dir
123 def get_std_script_dir
124 GRADER_ROOT + '/std-script'
124 GRADER_ROOT + '/std-script'
125 end
125 end
126
126
127 def copy_script(problem_home)
127 def copy_script(problem_home)
128 script_dir = "#{problem_home}/script"
128 script_dir = "#{problem_home}/script"
129 std_script_dir = get_std_script_dir
129 std_script_dir = get_std_script_dir
130
130
131 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
131 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
132
132
133 scripts = Dir[std_script_dir + '/*']
133 scripts = Dir[std_script_dir + '/*']
134
134
135 copied = []
135 copied = []
136
136
137 scripts.each do |s|
137 scripts.each do |s|
138 fname = File.basename(s)
138 fname = File.basename(s)
139 + next if FileTest.directory?(s)
139 if !FileTest.exist?("#{script_dir}/#{fname}")
140 if !FileTest.exist?("#{script_dir}/#{fname}")
140 copied << fname
141 copied << fname
141 FileUtils.cp(s, "#{script_dir}")
142 FileUtils.cp(s, "#{script_dir}")
142 end
143 end
143 end
144 end
144
145
145 return copied
146 return copied
146 end
147 end
147
148
148 def copy_log_filename(problem_home)
149 def copy_log_filename(problem_home)
149 return File.join(problem_home, '.scripts_copied')
150 return File.join(problem_home, '.scripts_copied')
150 end
151 end
151
152
152 def save_copy_log(problem_home, log)
153 def save_copy_log(problem_home, log)
153 f = File.new(copy_log_filename(problem_home),"w")
154 f = File.new(copy_log_filename(problem_home),"w")
154 log.each do |fname|
155 log.each do |fname|
155 f.write("#{fname}\n")
156 f.write("#{fname}\n")
156 end
157 end
157 f.close
158 f.close
158 end
159 end
159
160
160 def load_copy_log(problem_home)
161 def load_copy_log(problem_home)
161 f = File.new(copy_log_filename(problem_home),"r")
162 f = File.new(copy_log_filename(problem_home),"r")
162 log = []
163 log = []
163 f.readlines.each do |line|
164 f.readlines.each do |line|
164 log << line.strip
165 log << line.strip
165 end
166 end
166 f.close
167 f.close
167 log
168 log
168 end
169 end
169
170
170 def clear_copy_log(problem_home)
171 def clear_copy_log(problem_home)
171 File.delete(copy_log_filename(problem_home))
172 File.delete(copy_log_filename(problem_home))
172 end
173 end
173
174
174 def clear_script(log,problem_home)
175 def clear_script(log,problem_home)
175 log.each do |s|
176 log.each do |s|
176 FileUtils.rm("#{problem_home}/script/#{s}")
177 FileUtils.rm("#{problem_home}/script/#{s}")
177 end
178 end
178 end
179 end
179
180
180 def mkdir_if_does_not_exist(dirname)
181 def mkdir_if_does_not_exist(dirname)
181 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
182 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
182 end
183 end
183
184
184 end
185 end
185
186
186 end
187 end
@@ -1,59 +1,59
1 #
1 #
2 # This part contains various test_request helpers for interfacing
2 # This part contains various test_request helpers for interfacing
3 # with Grader::Engine. There are TestRequestRoomMaker and
3 # with Grader::Engine. There are TestRequestRoomMaker and
4 # TestRequestReporter.
4 # TestRequestReporter.
5
5
6 module Grader
6 module Grader
7
7
8 def self.link_or_copy(src, des)
8 def self.link_or_copy(src, des)
9 begin
9 begin
10 FileUtils.ln_s(src, des)
10 FileUtils.ln_s(src, des)
11 - rescue
11 + rescue NotImplementedError
12 FileUtils.cp(src,des)
12 FileUtils.cp(src,des)
13 end
13 end
14 end
14 end
15
15
16 def self.call_and_log(error_message)
16 def self.call_and_log(error_message)
17 begin
17 begin
18 yield
18 yield
19 rescue
19 rescue
20 msg = "ERROR: #{error_message}"
20 msg = "ERROR: #{error_message}"
21 raise msg
21 raise msg
22 end
22 end
23 end
23 end
24
24
25 #
25 #
26 # A TestRequestRoomMaker is a helper object for Engine
26 # A TestRequestRoomMaker is a helper object for Engine
27 # - finds grading room: in user_result_dir/(user)/test_request/ ...
27 # - finds grading room: in user_result_dir/(user)/test_request/ ...
28 # - prepare problem configuration for grading --- basically it copy
28 # - prepare problem configuration for grading --- basically it copy
29 # all config files, and copy user's input into the testcase
29 # all config files, and copy user's input into the testcase
30 # directory. First, it finds the template from problem template
30 # directory. First, it finds the template from problem template
31 # directory; if it can't find a template, it'll use the template
31 # directory; if it can't find a template, it'll use the template
32 # from default template.
32 # from default template.
33 class TestRequestRoomMaker
33 class TestRequestRoomMaker
34 def initialize
34 def initialize
35 @config = Grader::Configuration.get_instance
35 @config = Grader::Configuration.get_instance
36 end
36 end
37
37
38 def produce_grading_room(test_request)
38 def produce_grading_room(test_request)
39 grading_room = grading_room_dir(test_request)
39 grading_room = grading_room_dir(test_request)
40 FileUtils.mkdir_p(grading_room)
40 FileUtils.mkdir_p(grading_room)
41
41
42 #
42 #
43 # Also copy additional submitted file to this directory as well.
43 # Also copy additional submitted file to this directory as well.
44 # The program would see this file only if it is copied
44 # The program would see this file only if it is copied
45 # to the sandbox directory later. The run script should do it.
45 # to the sandbox directory later. The run script should do it.
46 #
46 #
47 if FileTest.exists?("#{test_request.input_file_name}.files")
47 if FileTest.exists?("#{test_request.input_file_name}.files")
48 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
48 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
49 "#{grading_room}")
49 "#{grading_room}")
50 end
50 end
51
51
52 grading_room
52 grading_room
53 end
53 end
54
54
55 def find_problem_home(test_request)
55 def find_problem_home(test_request)
56 problem_name = test_request.problem_name
56 problem_name = test_request.problem_name
57
57
58 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
58 template_dir = "#{@config.test_request_problem_templates_dir}/" + problem_name
59
59
You need to be logged in to leave comments. Login now