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,138 +1,175
1 1 require 'fileutils'
2 + require 'ftools'
3 + require 'lib/dir_init'
2 4
3 5 module Grader
4 6
5 7 #
6 8 # A grader engine grades a submission, against anything: a test
7 9 # data, or a user submitted test data. It uses two helpers objects:
8 10 # room_maker and reporter.
9 11 #
10 12 class Engine
11 13
12 14 attr_writer :room_maker
13 15 attr_writer :reporter
14 16
15 17 def initialize(room_maker=nil, reporter=nil)
16 18 @config = Grader::Configuration.get_instance
17 19
18 20 @room_maker = room_maker || Grader::SubmissionRoomMaker.new
19 21 @reporter = reporter || Grader::SubmissionReporter.new
20 22 end
21 23
22 24 # takes a submission, asks room_maker to produce grading directories,
23 25 # calls grader scripts, and asks reporter to save the result
24 26 def grade(submission)
25 27 current_dir = `pwd`.chomp
26 28
27 29 user = submission.user
28 30 problem = submission.problem
29 31
30 32 # TODO: will have to create real exception for this
31 33 if user==nil or problem == nil
32 34 @reporter.report_error(submission,"Grading error: problem with submission")
33 35 #raise "engine: user or problem is nil"
34 36 end
35 37
36 38 # TODO: this is another hack so that output only task can be judged
37 39 if submission.language!=nil
38 40 language = submission.language.name
39 41 lang_ext = submission.language.ext
40 42 else
41 43 language = 'c'
42 44 lang_ext = 'c'
43 45 end
44 46
45 47 # FIX THIS
46 48 talk 'some hack on language'
47 49 if language == 'cpp'
48 50 language = 'c++'
49 51 end
50 52
51 53 # COMMENT: should it be only source.ext?
52 54 if problem!=nil
53 55 source_name = "#{problem.name}.#{lang_ext}"
54 56 else
55 57 source_name = "source.#{lang_ext}"
56 58 end
57 59
58 60 begin
59 61 grading_dir = @room_maker.produce_grading_room(submission)
60 62 @room_maker.save_source(submission,source_name)
61 63 problem_home = @room_maker.find_problem_home(submission)
62 64
63 65 # puts "GRADING DIR: #{grading_dir}"
64 66 # puts "PROBLEM DIR: #{problem_home}"
65 67
68 + dinit = DirInit::Manager.new(problem_home)
69 +
70 + dinit.setup do
66 71 copy_log = copy_script(problem_home)
72 + save_copy_log(problem_home,copy_log)
73 + end
67 74
68 75 call_judge(problem_home,language,grading_dir,source_name)
69 76
70 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 82 clear_script(copy_log,problem_home)
83 + end
73 84
74 85 rescue RuntimeError => msg
75 86 @reporter.report_error(submission,"Grading error: #{msg}")
76 87
77 88 ensure
78 89 @room_maker.clean_up(submission)
79 90 Dir.chdir(current_dir) # this is really important
80 91 end
81 92 end
82 93
83 94 protected
84 95
85 96 def talk(str)
86 97 if @config.talkative
87 98 puts str
88 99 end
89 100 end
90 101
91 102 def call_judge(problem_home,language,grading_dir,fname)
92 103 ENV['PROBLEM_HOME'] = problem_home
93 104
94 105 talk grading_dir
95 106 Dir.chdir grading_dir
96 107 cmd = "#{problem_home}/script/judge #{language} #{fname}"
97 108 talk "CMD: #{cmd}"
98 109 system(cmd)
99 110 end
100 111
101 112 def get_std_script_dir
102 113 GRADER_ROOT + '/std-script'
103 114 end
104 115
105 116 def copy_script(problem_home)
106 117 script_dir = "#{problem_home}/script"
107 118 std_script_dir = get_std_script_dir
108 119
109 120 raise "std-script directory not found" if !FileTest.exist?(std_script_dir)
110 121
111 122 scripts = Dir[std_script_dir + '/*']
112 123
113 124 copied = []
114 125
115 126 scripts.each do |s|
116 127 fname = File.basename(s)
117 128 if !FileTest.exist?("#{script_dir}/#{fname}")
118 129 copied << fname
119 130 system("cp #{s} #{script_dir}")
120 131 end
121 132 end
122 133
123 134 return copied
124 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 163 def clear_script(log,problem_home)
127 164 log.each do |s|
128 165 system("rm #{problem_home}/script/#{s}")
129 166 end
130 167 end
131 168
132 169 def mkdir_if_does_not_exist(dirname)
133 170 Dir.mkdir(dirname) if !FileTest.exist?(dirname)
134 171 end
135 172
136 173 end
137 174
138 175 end
You need to be logged in to leave comments. Login now