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: 148 inserted, 2 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,25 +1,27
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
14
16
15 def initialize(room_maker=nil, reporter=nil)
17 def initialize(room_maker=nil, reporter=nil)
16 @config = Grader::Configuration.get_instance
18 @config = Grader::Configuration.get_instance
17
19
18 @room_maker = room_maker || Grader::SubmissionRoomMaker.new
20 @room_maker = room_maker || Grader::SubmissionRoomMaker.new
19 @reporter = reporter || Grader::SubmissionReporter.new
21 @reporter = reporter || Grader::SubmissionReporter.new
20 end
22 end
21
23
22 # takes a submission, asks room_maker to produce grading directories,
24 # takes a submission, asks room_maker to produce grading directories,
23 # calls grader scripts, and asks reporter to save the result
25 # calls grader scripts, and asks reporter to save the result
24 def grade(submission)
26 def grade(submission)
25 current_dir = `pwd`.chomp
27 current_dir = `pwd`.chomp
@@ -42,55 +44,64
42 lang_ext = 'c'
44 lang_ext = 'c'
43 end
45 end
44
46
45 # FIX THIS
47 # FIX THIS
46 talk 'some hack on language'
48 talk 'some hack on language'
47 if language == 'cpp'
49 if language == 'cpp'
48 language = 'c++'
50 language = 'c++'
49 end
51 end
50
52
51 # COMMENT: should it be only source.ext?
53 # COMMENT: should it be only source.ext?
52 if problem!=nil
54 if problem!=nil
53 source_name = "#{problem.name}.#{lang_ext}"
55 source_name = "#{problem.name}.#{lang_ext}"
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
66 - copy_log = copy_script(problem_home)
68 + dinit = DirInit::Manager.new(problem_home)
69 +
70 + dinit.setup do
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
72 - clear_script(copy_log,problem_home)
79 + dinit.teardown do
80 + copy_log = load_copy_log(problem_home)
81 + clear_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
85 def talk(str)
96 def talk(str)
86 if @config.talkative
97 if @config.talkative
87 puts str
98 puts str
88 end
99 end
89 end
100 end
90
101
91 def call_judge(problem_home,language,grading_dir,fname)
102 def call_judge(problem_home,language,grading_dir,fname)
92 ENV['PROBLEM_HOME'] = problem_home
103 ENV['PROBLEM_HOME'] = problem_home
93
104
94 talk grading_dir
105 talk grading_dir
95 Dir.chdir grading_dir
106 Dir.chdir grading_dir
96 cmd = "#{problem_home}/script/judge #{language} #{fname}"
107 cmd = "#{problem_home}/script/judge #{language} #{fname}"
@@ -101,38 +112,64
101 def get_std_script_dir
112 def get_std_script_dir
102 GRADER_ROOT + '/std-script'
113 GRADER_ROOT + '/std-script'
103 end
114 end
104
115
105 def copy_script(problem_home)
116 def copy_script(problem_home)
106 script_dir = "#{problem_home}/script"
117 script_dir = "#{problem_home}/script"
107 std_script_dir = get_std_script_dir
118 std_script_dir = get_std_script_dir
108
119
109 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
120 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
110
121
111 scripts = Dir[std_script_dir + '/*']
122 scripts = Dir[std_script_dir + '/*']
112
123
113 copied = []
124 copied = []
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
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
125
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
138 end
175 end
You need to be logged in to leave comments. Login now