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,7 +1,9
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:
@@ -60,19 +62,28
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)
@@ -120,12 +131,38
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
You need to be logged in to leave comments. Login now