Description:
add some lock in task git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@55 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

r30:c1451a367614 - - 9 files changed: 169 inserted, 6 deleted

@@ -0,0 +1,17
1 + class AddStatusToTasks < ActiveRecord::Migration
2 + def self.up
3 + add_column :tasks, :status, :integer
4 + add_column :tasks, :updated_at, :datetime
5 +
6 + Task.reset_column_information
7 + Task.find(:all).each do |task|
8 + task.status_complete
9 + task.save
10 + end
11 + end
12 +
13 + def self.down
14 + remove_column :tasks, :updated_at
15 + remove_column :tasks, :status
16 + end
17 + end
@@ -0,0 +1,16
1 + ENV["RAILS_ENV"] = "test"
2 + require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
3 +
4 + def take_wait_return
5 + task = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
6 + sleep (rand)/10.0
7 + task.status_complete
8 + task.save!
9 + end
10 +
11 + n = 300
12 +
13 + n.times do |i|
14 + take_wait_return
15 + puts i
16 + end
@@ -0,0 +1,18
1 + ENV["RAILS_ENV"] = "test"
2 + require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
3 +
4 + def clear_all_tasks
5 + Task.find(:all).each do |task|
6 + task.destroy
7 + end
8 + end
9 +
10 +
11 + clear_all_tasks
12 +
13 + (1..1000).each do |i|
14 + Task.create(:id => i,
15 + :submission_id => i,
16 + :status => Task::STATUS_INQUEUE)
17 + end
18 +
@@ -0,0 +1,14
1 + ENV["RAILS_ENV"] = "test"
2 + require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
3 +
4 + def clear_all_tasks
5 + Task.find(:all).each do |task|
6 + task.destroy
7 + end
8 + end
9 +
10 + puts Task.find(:all,
11 + :conditions => {:status => Task::STATUS_COMPLETE}).length
12 +
13 + clear_all_tasks
14 +
@@ -1,2 +1,40
1 1 class Task < ActiveRecord::Base
2 +
3 + STATUS_GRADING = 0
4 + STATUS_INQUEUE = 1
5 + STATUS_COMPLETE = 2
6 +
7 + def status_inqueue
8 + self.status = Task::STATUS_INQUEUE
2 9 end
10 +
11 + def status_grading
12 + self.status = Task::STATUS_GRADING
13 + end
14 +
15 + def status_complete
16 + self.status = Task::STATUS_COMPLETE
17 + end
18 +
19 + def self.get_inqueue_and_change_status(status)
20 + task = nil
21 + begin
22 + Task.transaction do
23 + task = Task.find(:first,
24 + :order => "created_at",
25 + :conditions => {:status=> Task::STATUS_INQUEUE},
26 + :lock => true)
27 + if task!=nil
28 + task.status = status
29 + task.save!
30 + end
31 + end
32 +
33 + rescue
34 + task = nil
35 +
36 + end
37 + task
38 + end
39 +
40 + end
@@ -1,15 +1,16
1 1 class AddLanguageExt < ActiveRecord::Migration
2 2 def self.up
3 3 add_column :languages, :ext, :string, :limit => 10
4 4
5 + Language.reset_column_information
5 6 langs = Language.find(:all)
6 7 langs.each do |l|
7 8 l.ext = l.name
8 9 l.save
9 10 end
10 11 end
11 12
12 13 def self.down
13 14 remove_column :languages, :ext
14 15 end
15 16 end
@@ -1,36 +1,36
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of ActiveRecord to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 14) do
12 + ActiveRecord::Schema.define(:version => 15) do
13 13
14 14 create_table "grader_processes", :force => true do |t|
15 15 t.string "ip", :limit => 20
16 16 t.integer "pid"
17 17 t.string "mode"
18 18 t.boolean "active"
19 19 t.datetime "created_at"
20 20 t.datetime "updated_at"
21 21 end
22 22
23 23 add_index "grader_processes", ["ip", "pid"], :name => "index_grader_processes_on_ip_and_pid"
24 24
25 25 create_table "languages", :force => true do |t|
26 26 t.string "name", :limit => 10
27 27 t.string "pretty_name"
28 28 t.string "ext", :limit => 10
29 29 end
30 30
31 31 create_table "problems", :force => true do |t|
32 32 t.string "name", :limit => 30
33 33 t.string "full_name"
34 34 t.integer "full_score"
35 35 t.date "date_added"
36 36 t.boolean "available"
@@ -68,38 +68,40
68 68 end
69 69
70 70 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
71 71 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
72 72
73 73 create_table "submissions", :force => true do |t|
74 74 t.integer "user_id"
75 75 t.integer "problem_id"
76 76 t.integer "language_id"
77 77 t.text "source"
78 78 t.binary "binary"
79 79 t.datetime "submitted_at"
80 80 t.datetime "compiled_at"
81 81 t.text "compiler_message"
82 82 t.datetime "graded_at"
83 83 t.integer "points"
84 84 t.text "grader_comment"
85 85 end
86 86
87 87 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
88 88
89 89 create_table "tasks", :force => true do |t|
90 90 t.integer "submission_id"
91 91 t.datetime "created_at"
92 + t.integer "status"
93 + t.datetime "updated_at"
92 94 end
93 95
94 96 create_table "users", :force => true do |t|
95 97 t.string "login", :limit => 10
96 98 t.string "full_name"
97 99 t.string "hashed_password"
98 100 t.string "salt", :limit => 5
99 101 t.string "alias"
100 102 t.string "email"
101 103 end
102 104
103 105 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
104 106
105 107 end
@@ -1,5 +1,31
1 1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 - one:
2 +
3 + sub1:
3 4 id: 1
4 - two:
5 + submission_id: 1
6 + status: <%= Task::STATUS_COMPLETE %>
7 + created_at: <%= Time.local(2000,1,1,10,10) %>
8 +
9 + sub2:
5 10 id: 2
11 + submission_id: 2
12 + status: <%= Task::STATUS_GRADING %>
13 + created_at: <%= Time.local(2000,1,1,10,20) %>
14 +
15 + sub3:
16 + id: 3
17 + submission_id: 3
18 + status: <%= Task::STATUS_INQUEUE %>
19 + created_at: <%= Time.local(2000,1,1,10,30) %>
20 +
21 + sub4:
22 + id: 4
23 + submission_id: 4
24 + status: <%= Task::STATUS_INQUEUE %>
25 + created_at: <%= Time.local(2000,1,1,10,40) %>
26 +
27 + sub5:
28 + id: 5
29 + submission_id: 5
30 + status: <%= Task::STATUS_INQUEUE %>
31 + created_at: <%= Time.local(2000,1,1,10,50) %>
@@ -1,10 +1,41
1 1 require File.dirname(__FILE__) + '/../test_helper'
2 2
3 3 class TaskTest < Test::Unit::TestCase
4 4 fixtures :tasks
5 5
6 - # Replace this with your real tests.
7 - def test_truth
8 - assert true
6 + self.use_transactional_fixtures = false
7 +
8 + def test_get_inqueue_simple
9 + task1 = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
10 +
11 + assert_equal task1.id, 3, "should get the earliest task"
12 + assert_equal task1.status, Task::STATUS_GRADING, "status changes"
13 +
14 + task2 = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
15 +
16 + assert_equal task2.id, 4, "should get the next task"
17 + assert_equal task2.status, Task::STATUS_GRADING, "status changes"
18 + end
19 +
20 + def generate_tasks(n)
21 + n.times do |i|
22 + Task.create(:submission_id => i,
23 + :status => Task::STATUS_INQUEUE,
24 + :create_at => Time.now + i.minutes)
9 25 end
10 26 end
27 +
28 + # use the process version in /test/concurrent instead
29 + def UNUSED_test_get_inqueue_concurrent
30 + ActiveRecord::Base.allow_concurrency = true
31 +
32 + task1 = Task.get_inqueue_and_change_status(Task::STATUS_GRADING)
33 +
34 + assert_equal task1.id, 3, "should get the earliest task"
35 + assert_equal task1.status, Task::STATUS_GRADING, "status changes"
36 +
37 + ActiveRecord::Base.verify_active_connections!
38 + end
39 +
40 + end
41 +
You need to be logged in to leave comments. Login now