Description:
MERGED changeset 380:381 from http://theory.cpe.ku.ac.th/grader/web/trunk/judge/scripts git-svn-id: http://theory.cpe.ku.ac.th/grader/judge/trunk/scripts@382 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r71:76c4d891d4d5 - - 3 files changed: 146 inserted, 0 deleted

@@ -0,0 +1,107
1 + require 'ftools'
2 +
3 + # DirInit::Manager handles directory initialization and clean-up when
4 + # there are many concurrent processes that wants to modify the
5 + # directory in the same way.
6 + #
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
9 + # job. Problems may occur when the first process delete the files
10 + # while the second process is still using the files.
11 + #
12 + # This library maintain a reference counter on the processes using the
13 + # directory. It locks the dir to manage critical section when
14 + # updating the reference counter.
15 +
16 + module DirInit
17 +
18 + class Manager
19 +
20 + def initialize(dir_name, usage_filename='.usage_counter')
21 + @dir_name = dir_name
22 + @usage_filename = usage_filename
23 + end
24 +
25 + # Check if someone has initialized the dir. If not, call block.
26 +
27 + def setup # :yields: block
28 + dir = File.new(@dir_name)
29 + dir.flock(File::LOCK_EX)
30 + begin
31 + counter_filename = get_counter_filename
32 + if File.exist? counter_filename
33 + # someone is here
34 + f = File.new(counter_filename,"r+")
35 + counter = f.read.to_i
36 + f.seek(0)
37 + f.write("#{counter+1}\n")
38 + f.close
39 + else
40 + # i'm the first, create the counter file
41 + counter = 0
42 + f = File.new(counter_filename,"w")
43 + f.write("1\n")
44 + f.close
45 + end
46 +
47 + # if no one is here
48 + if counter == 0
49 + if block_given?
50 + yield
51 + end
52 + end
53 +
54 + rescue
55 + raise
56 +
57 + ensure
58 + # make sure it unlock the directory
59 + dir.flock(File::LOCK_UN)
60 + end
61 + end
62 +
63 + # Check if I am the last one using the dir. If true, call block.
64 +
65 + def teardown
66 + dir = File.new(@dir_name)
67 + dir.flock(File::LOCK_EX)
68 + begin
69 + counter_filename = get_counter_filename
70 + if File.exist? counter_filename
71 + # someone is here
72 + f = File.new(counter_filename,"r+")
73 + counter = f.read.to_i
74 + f.seek(0)
75 + f.write("#{counter-1}\n")
76 + f.close
77 +
78 + if counter == 1
79 + # i'm the last one
80 +
81 + File.delete(counter_filename)
82 + if block_given?
83 + yield
84 + end
85 + end
86 + else
87 + # This is BAD
88 + raise "Error: reference count missing"
89 + end
90 +
91 + rescue
92 + raise
93 +
94 + ensure
95 + # make sure it unlock the directory
96 + dir.flock(File::LOCK_UN)
97 + end
98 + end
99 +
100 + protected
101 +
102 + def get_counter_filename
103 + return File.join(@dir_name,@usage_filename)
104 + end
105 +
106 + end
107 + end
@@ -0,0 +1,2
1 + box
2 +
@@ -1,13 +1,15
1 require 'fileutils'
1 require 'fileutils'
2 + require 'ftools'
3 + require 'lib/dir_init'
2
4
3 module Grader
5 module Grader
4
6
5 #
7 #
6 # A grader engine grades a submission, against anything: a test
8 # A grader engine grades a submission, against anything: a test
7 # data, or a user submitted test data. It uses two helpers objects:
9 # data, or a user submitted test data. It uses two helpers objects:
8 # room_maker and reporter.
10 # room_maker and reporter.
9 #
11 #
10 class Engine
12 class Engine
11
13
12 attr_writer :room_maker
14 attr_writer :room_maker
13 attr_writer :reporter
15 attr_writer :reporter
@@ -54,31 +56,40
54 else
56 else
55 source_name = "source.#{lang_ext}"
57 source_name = "source.#{lang_ext}"
56 end
58 end
57
59
58 begin
60 begin
59 grading_dir = @room_maker.produce_grading_room(submission)
61 grading_dir = @room_maker.produce_grading_room(submission)
60 @room_maker.save_source(submission,source_name)
62 @room_maker.save_source(submission,source_name)
61 problem_home = @room_maker.find_problem_home(submission)
63 problem_home = @room_maker.find_problem_home(submission)
62
64
63 # puts "GRADING DIR: #{grading_dir}"
65 # puts "GRADING DIR: #{grading_dir}"
64 # puts "PROBLEM DIR: #{problem_home}"
66 # puts "PROBLEM DIR: #{problem_home}"
65
67
68 + dinit = DirInit::Manager.new(problem_home)
69 +
70 + dinit.setup do
66 copy_log = copy_script(problem_home)
71 copy_log = copy_script(problem_home)
72 + save_copy_log(problem_home,copy_log)
73 + end
67
74
68 call_judge(problem_home,language,grading_dir,source_name)
75 call_judge(problem_home,language,grading_dir,source_name)
69
76
70 @reporter.report(submission,"#{grading_dir}/test-result")
77 @reporter.report(submission,"#{grading_dir}/test-result")
71
78
79 + dinit.teardown do
80 + copy_log = load_copy_log(problem_home)
81 + clear_copy_log(problem_home)
72 clear_script(copy_log,problem_home)
82 clear_script(copy_log,problem_home)
83 + end
73
84
74 rescue RuntimeError => msg
85 rescue RuntimeError => msg
75 @reporter.report_error(submission,"Grading error: #{msg}")
86 @reporter.report_error(submission,"Grading error: #{msg}")
76
87
77 ensure
88 ensure
78 @room_maker.clean_up(submission)
89 @room_maker.clean_up(submission)
79 Dir.chdir(current_dir) # this is really important
90 Dir.chdir(current_dir) # this is really important
80 end
91 end
81 end
92 end
82
93
83 protected
94 protected
84
95
@@ -114,24 +125,50
114
125
115 scripts.each do |s|
126 scripts.each do |s|
116 fname = File.basename(s)
127 fname = File.basename(s)
117 if !FileTest.exist?("#{script_dir}/#{fname}")
128 if !FileTest.exist?("#{script_dir}/#{fname}")
118 copied << fname
129 copied << fname
119 system("cp #{s} #{script_dir}")
130 system("cp #{s} #{script_dir}")
120 end
131 end
121 end
132 end
122
133
123 return copied
134 return copied
124 end
135 end
125
136
137 + def copy_log_filename(problem_home)
138 + return File.join(problem_home, '.scripts_copied')
139 + end
140 +
141 + def save_copy_log(problem_home, log)
142 + f = File.new(copy_log_filename(problem_home),"w")
143 + log.each do |fname|
144 + f.write("#{fname}\n")
145 + end
146 + f.close
147 + end
148 +
149 + def load_copy_log(problem_home)
150 + f = File.new(copy_log_filename(problem_home),"r")
151 + log = []
152 + f.readlines.each do |line|
153 + log << line.strip
154 + end
155 + f.close
156 + log
157 + end
158 +
159 + def clear_copy_log(problem_home)
160 + File.delete(copy_log_filename(problem_home))
161 + end
162 +
126 def clear_script(log,problem_home)
163 def clear_script(log,problem_home)
127 log.each do |s|
164 log.each do |s|
128 system("rm #{problem_home}/script/#{s}")
165 system("rm #{problem_home}/script/#{s}")
129 end
166 end
130 end
167 end
131
168
132 def mkdir_if_does_not_exist(dirname)
169 def mkdir_if_does_not_exist(dirname)
133 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
170 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
134 end
171 end
135
172
136 end
173 end
137
174
You need to be logged in to leave comments. Login now