pwrake 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/pwrake/shell.rb CHANGED
@@ -36,7 +36,7 @@ module Pwrake
36
36
  TLEN.times{ @terminator << CHARS[rand(CHARS.length)] }
37
37
  end
38
38
 
39
- attr_reader :id
39
+ attr_reader :id, :host
40
40
  attr_accessor :current_task
41
41
 
42
42
  def system_cmd(*arg)
@@ -95,18 +95,22 @@ module Pwrake
95
95
  command = command.join(' ')
96
96
  Log.debug "--- command=#{command.inspect}"
97
97
  @lock.synchronize do
98
- _execute(command){|x| LOCK.synchronize{puts x}}
98
+ _execute(command){|x| Log.stdout_puts x}
99
99
  end
100
+ @status == 0
100
101
  end
101
102
 
102
103
  def cd_work_dir
103
- _system("cd #{@work_dir}")
104
+ _system("cd #{@work_dir}") or die
104
105
  end
105
106
 
106
107
  def cd(dir="")
107
- _system("cd #{dir}")
108
+ _system("cd #{dir}") or die
108
109
  end
109
110
 
111
+ def die
112
+ raise "Failed at #{@host}, id=#{@id}, cmd='#{@cmd}'"
113
+ end
110
114
 
111
115
  END {
112
116
  OPEN_LIST.map do |k,v|
@@ -118,6 +122,7 @@ module Pwrake
118
122
  private
119
123
 
120
124
  def _system(cmd)
125
+ @cmd = cmd
121
126
  raise "@io is closed" if @io.closed?
122
127
  @lock.synchronize do
123
128
  @io.puts(cmd+"\necho '#{@terminator}':$? ")
@@ -126,15 +131,30 @@ module Pwrake
126
131
  end
127
132
  end
128
133
 
134
+ def _backquote(cmd)
135
+ @cmd = cmd
136
+ raise "@io is closed" if @io.closed?
137
+ a = []
138
+ @lock.synchronize do
139
+ @io.puts(cmd+"\necho '#{@terminator}':$? ")
140
+ status = io_read_loop{|x| a << x}
141
+ end
142
+ a.join("\n")
143
+ end
144
+
129
145
  def _execute(cmd,quote=nil,&block)
146
+ @cmd = cmd
130
147
  raise "@io is closed" if @io.closed?
148
+ status = nil
131
149
  start_time = Time.now
132
- @io.puts @@profiler.command(cmd,@terminator)
133
- status = io_read_loop(&block)
134
- end_time = Time.now
135
- @status = @@profiler.profile(@current_task, cmd,
136
- start_time, end_time, status)
137
- @status == 0
150
+ begin
151
+ @io.puts @@profiler.command(cmd,@terminator)
152
+ status = io_read_loop(&block)
153
+ ensure
154
+ end_time = Time.now
155
+ @status = @@profiler.profile(@current_task, cmd,
156
+ start_time, end_time, host, status)
157
+ end
138
158
  end
139
159
 
140
160
  def io_read_loop
@@ -13,50 +13,115 @@ module Pwrake
13
13
  @location = a
14
14
  end
15
15
 
16
+ def task_id
17
+ @task_id
18
+ end
16
19
 
17
20
  def invoke_modify(*args)
21
+ return if @already_invoked
22
+
18
23
  application.start_worker
19
- task_args = TaskArguments.new(arg_names, args)
20
- flag = application.pwrake_options['HALT_QUEUE_WHILE_SEARCH']
21
- start_time = Time.now
22
- if flag
23
- application.task_queue.enq_synchronize do
24
- search_with_call_chain(self, task_args, InvocationChain::EMPTY)
25
- end
24
+
25
+ if false
26
+ th = Thread.new(args){|a| pw_search_tasks(a) }
26
27
  else
27
- search_with_call_chain(self, task_args, InvocationChain::EMPTY)
28
+ pw_search_tasks(args)
29
+ th = nil
28
30
  end
29
- Log.info "-- search_tasks %.6fs" % (Time.now-start_time)
30
- return if @already_invoked
31
31
 
32
32
  if conn = Pwrake.current_shell
33
- @waiting_thread = nil
34
33
  application.thread_loop(conn,self)
35
34
  else
36
- @waiting_thread = Thread.current
37
- Log.debug "--- sleep in invoke_modify #{self.name} #{@waiting_thread.inspect}"
38
- sleep
39
- Log.debug "--- awake in invoke_modify"
40
- pw_invoke
35
+ while true
36
+ t = application.finish_queue.deq
37
+ break if t==self
38
+ #application.postprocess(t) # <---------
39
+ #t.pw_enq_subsequents # <---------
40
+ end
41
41
  end
42
+
43
+ th.join if th
42
44
  end
43
45
 
46
+ def pw_search_tasks(args)
47
+ task_args = TaskArguments.new(arg_names, args)
48
+ timer = Timer.new("search_task")
49
+ h = application.pwrake_options['HALT_QUEUE_WHILE_SEARCH']
50
+ application.task_queue.synchronize(h) do
51
+ search_with_call_chain(self, task_args, InvocationChain::EMPTY)
52
+ end
53
+ timer.finish
54
+ end
44
55
 
45
56
  def pw_invoke
46
- shell = Pwrake.current_shell
47
- if shell
57
+ time_start = Time.now
58
+ if shell = Pwrake.current_shell
48
59
  shell.current_task = self
49
- log_host(shell.host)
60
+ #host = shell.host
61
+ #log_host(host)
50
62
  end
63
+
51
64
  @lock.synchronize do
52
65
  return if @already_invoked
53
66
  @already_invoked = true
54
67
  end
55
68
  pw_execute(@arg_data) if needed?
56
- start_time = Time.now
57
- pw_enq_subsequents
58
- Log.info "-- pw_enq_subsequents(%s) %.6fs"%[self.name,Time.now-start_time]
69
+ if kind_of?(Rake::FileTask)
70
+ application.postprocess(self) # <---------
71
+ @file_stat = File::Stat.new(name)
72
+ end
73
+ log_task(time_start)
74
+ application.finish_queue.enq(self)
59
75
  shell.current_task = nil if shell
76
+ pw_enq_subsequents # <---------
77
+ end
78
+
79
+ def log_task(time_start)
80
+ return if !application.task_logger
81
+ time_end = Time.now
82
+ row = [ @task_id, name,
83
+ time_start, time_end, time_end-time_start,
84
+ @prerequisites.join('|')
85
+ ]
86
+
87
+ if loc = suggest_location()
88
+ row << loc.join('|')
89
+ else
90
+ row << ''
91
+ end
92
+
93
+ if shell = Pwrake.current_shell
94
+ row.concat [shell.host, shell.id]
95
+ else
96
+ row.concat ['','']
97
+ end
98
+
99
+ row << ((@actions.empty?) ? 0 : 1)
100
+ row << ((@executed) ? 1 : 0)
101
+
102
+ if loc && !loc.empty? && shell && !@actions.empty?
103
+ Pwrake.application.count( loc, shell.host )
104
+ end
105
+
106
+ if @file_stat
107
+ row.concat [@file_stat.size, @file_stat.mtime, self.location.join('|')]
108
+ else
109
+ row.concat ['','','']
110
+ end
111
+
112
+ s = row.map do |x|
113
+ if x.kind_of?(Time)
114
+ Profiler.format_time(x)
115
+ elsif x.kind_of?(String) && x!=''
116
+ '"'+x+'"'
117
+ else
118
+ x.to_s
119
+ end
120
+ end.join(',')
121
+
122
+ # task_id task_name start_time end_time elap_time preq preq_host
123
+ # exec_host shell_id has_action executed file_size file_mtime file_host
124
+ application.task_logger.print s+"\n"
60
125
  end
61
126
 
62
127
 
@@ -71,41 +136,53 @@ module Pwrake
71
136
  Log.info "** Execute #{name}"
72
137
  end
73
138
  application.enhance_with_matching_rule(name) if @actions.empty?
74
- @actions.each do |act|
75
- case act.arity
76
- when 1
77
- act.call(self)
78
- else
79
- act.call(self, args)
139
+ begin
140
+ @actions.each do |act|
141
+ case act.arity
142
+ when 1
143
+ act.call(self)
144
+ else
145
+ act.call(self, args)
146
+ end
147
+ end
148
+ rescue Exception=>e
149
+ if kind_of?(Rake::FileTask) && File.exist?(name)
150
+ opt = application.pwrake_options['FAILED_TARGET']||"rename"
151
+ case opt
152
+ when /rename/i
153
+ dst = name+"._fail_"
154
+ ::FileUtils.mv(name,dst)
155
+ msg = "Rename failed target file '#{name}' to '#{dst}'"
156
+ Log.stderr_puts(msg)
157
+ when /delete/i
158
+ ::FileUtils.rm(name)
159
+ msg = "Delete failed target file '#{name}'"
160
+ Log.stderr_puts(msg)
161
+ when /leave/i
162
+ end
80
163
  end
164
+ raise e
81
165
  end
166
+ @executed = true if !@actions.empty?
82
167
  end
83
168
 
84
169
  def pw_enq_subsequents
85
170
  @lock.synchronize do
86
- my_name = self.name
87
- application.task_queue.enq_synchronize do
88
- @subsequents.each do |t| # <<--- competition !!!
89
- t && t.check_and_enq(my_name)
171
+ @subsequents.each do |t| # <<--- competition !!!
172
+ if t && t.check_prereq_finished(self.name)
173
+ application.task_queue.enq(t)
90
174
  end
91
- @already_finished = true # <<--- competition !!!
92
175
  end
176
+ @already_finished = true # <<--- competition !!!
93
177
  end
94
178
  end
95
179
 
96
- def check_and_enq(preq_name=nil)
180
+ def check_prereq_finished(preq_name=nil)
97
181
  @unfinished_prereq.delete(preq_name)
98
- if @unfinished_prereq.empty?
99
- if @waiting_thread
100
- Log.debug "--- @waiting_thread.wakeup name=#{self.name} "
101
- @waiting_thread.wakeup
102
- else
103
- Log.debug "--- check_and_enq enq name=#{self.name} "
104
- application.task_queue.enq(self)
105
- end
106
- end
182
+ @unfinished_prereq.empty?
107
183
  end
108
184
 
185
+
109
186
  # Same as search, but explicitly pass a call chain to detect
110
187
  # circular dependencies.
111
188
  def search_with_call_chain(subseq, task_args, invocation_chain) # :nodoc:
@@ -122,7 +199,16 @@ module Pwrake
122
199
  if ! @already_searched
123
200
  @already_searched = true
124
201
  @arg_data = task_args
125
- search_prerequisites(task_args, new_chain)
202
+ if @prerequisites.empty?
203
+ @unfinished_prereq = {}
204
+ else
205
+ search_prerequisites(task_args, new_chain)
206
+ end
207
+ @task_id = application.task_id_counter
208
+ #check_and_enq
209
+ if @unfinished_prereq.empty?
210
+ application.task_queue.enq(self)
211
+ end
126
212
  end
127
213
  return false
128
214
  end
@@ -140,7 +226,6 @@ module Pwrake
140
226
  @unfinished_prereq.delete(prereq.name)
141
227
  end
142
228
  }
143
- check_and_enq
144
229
  end
145
230
 
146
231
  # Format the trace flags for display.
@@ -153,18 +238,57 @@ module Pwrake
153
238
  end
154
239
  private :format_search_flags
155
240
 
241
+ def file_size
242
+ @file_stat ? @file_stat.size : 0
243
+ end
244
+
245
+ def prior?
246
+ kind_of?(Rake::FileTask) && !@prerequisites.empty?
247
+ end
248
+
249
+ def suggest_location
250
+ if prior? && @suggest_location.nil?
251
+ @suggest_location = []
252
+ loc_fsz = Hash.new(0)
253
+ @prerequisites.each do |preq|
254
+ t = application[preq]
255
+ loc = t.location
256
+ fsz = t.file_size
257
+ if loc && fsz > 0
258
+ loc.each do |h|
259
+ loc_fsz[h] += fsz
260
+ end
261
+ end
262
+ end
263
+ if !loc_fsz.empty?
264
+ half_max_fsz = loc_fsz.values.max / 2
265
+ Log.debug "--- loc_fsz=#{loc_fsz.inspect} half_max_fsz=#{half_max_fsz}"
266
+ loc_fsz.each do |h,sz|
267
+ if sz > half_max_fsz
268
+ @suggest_location << h
269
+ end
270
+ end
271
+ end
272
+ end
273
+ @suggest_location
274
+ end
275
+
276
+ def suggest_location2
277
+ if kind_of?(Rake::FileTask) && preq_name = @prerequisites[0]
278
+ application[preq_name].location
279
+ end
280
+ end
156
281
 
157
282
  def log_host(exec_host)
158
283
  # exec_host = Pwrake.current_shell.host
159
- prereq_name = @prerequisites[0]
160
- if kind_of?(Rake::FileTask) and prereq_name
161
- Pwrake.application.count( @location, exec_host )
162
- if @location and @location.include? exec_host
284
+ if loc = suggest_location()
285
+ Pwrake.application.count( loc, exec_host )
286
+ if loc.include? exec_host
163
287
  compare = "=="
164
288
  else
165
289
  compare = "!="
166
290
  end
167
- Log.info "-- access to #{prereq_name}: file_host=#{@location.inspect} #{compare} exec_host=#{exec_host}"
291
+ Log.info "-- access to #{@prerequisites[0]}: file_host=#{loc.inspect} #{compare} exec_host=#{exec_host}"
168
292
  end
169
293
  end
170
294
 
@@ -1,17 +1,93 @@
1
1
  module Pwrake
2
2
 
3
+ class TaskConditionVariable < ConditionVariable
4
+ def signal(hint=nil)
5
+ super()
6
+ end
7
+ end
8
+
9
+ class PriorityQueueArray < Array
10
+ def push(t)
11
+ task_id = t.task_id
12
+ if empty? || last.task_id <= task_id
13
+ super(t)
14
+ elsif first.task_id > task_id
15
+ unshift(t)
16
+ else
17
+ lower = 0
18
+ upper = size-1
19
+ while lower+1 < upper
20
+ mid = ((lower + upper) / 2).to_i
21
+ if self[mid].task_id <= task_id
22
+ lower = mid
23
+ else
24
+ upper = mid
25
+ end
26
+ end
27
+ insert(upper,t)
28
+ end
29
+ end
30
+
31
+ def index(t)
32
+ if size < 40
33
+ return super(t)
34
+ end
35
+ task_id = t.task_id
36
+ if last.task_id < task_id || first.task_id > task_id
37
+ nil
38
+ else
39
+ lower = 0
40
+ upper = size-1
41
+ while lower+1 < upper
42
+ mid = ((lower + upper) / 2).to_i
43
+ if self[mid].task_id < task_id
44
+ lower = mid
45
+ else
46
+ upper = mid
47
+ end
48
+ end
49
+ mid = upper
50
+ if self[mid].task_id == task_id
51
+ Log.debug "--- TQA#index=#{mid}, task_id=#{task_id}"
52
+ mid
53
+ end
54
+ end
55
+ end
56
+ end # PriorityQueueArray
57
+
58
+ class LifoQueueArray < Array
59
+ def shift
60
+ pop
61
+ end
62
+ end
63
+
3
64
  class TaskQueue
4
65
 
5
66
  def initialize(*args)
6
67
  @finished = false
7
68
  @halt = false
8
69
  @mutex = Mutex.new
9
- @cv = ConditionVariable.new
10
70
  @th_end = []
11
71
  @enable_steal = true
12
- @q = []
13
72
  @reservation = {}
14
73
  @reserved_q = {}
74
+ case Pwrake.application.pwrake_options['QUEUE_PRIORITY']||"DFS"
75
+ when /dfs/i
76
+ @array_class = PriorityQueueArray
77
+ when /fifo/i
78
+ @array_class = Array
79
+ when /lifo/i
80
+ @array_class = LifoQueueArray
81
+ else
82
+ raise RuntimeError,"unknown option for QUEUE_PRIORITY"
83
+ end
84
+ init_queue(*args)
85
+ end
86
+
87
+ def init_queue(*args)
88
+ @cv = TaskConditionVariable.new
89
+ @q_prior = @array_class.new
90
+ @q_later = Array.new
15
91
  end
16
92
 
17
93
  attr_reader :mutex
@@ -34,15 +110,20 @@ module Pwrake
34
110
  end
35
111
  end
36
112
 
37
- def enq_synchronize
38
- if @halt
39
- ret = yield
40
- else
41
- @mutex.synchronize do
113
+ def synchronize(condition)
114
+ ret = nil
115
+ if condition
116
+ @mutex.lock
117
+ @halt = true
118
+ begin
42
119
  ret = yield
43
- enq_finish
120
+ @cv.broadcast
121
+ ensure
122
+ @halt = false
123
+ @mutex.unlock
44
124
  end
45
- @cv.broadcast
125
+ else
126
+ ret = yield
46
127
  end
47
128
  @reserved_q.keys.each do |th|
48
129
  Log.debug "--- run #{th}";
@@ -51,36 +132,15 @@ module Pwrake
51
132
  ret
52
133
  end
53
134
 
54
- def enq_finish
55
- end
56
-
57
-
58
- def enq(item,hint=nil)
59
- if th = @reservation[item]
60
- @reserved_q[th] = item
61
- else
62
- enq_impl(item,hint)
63
- end
64
- end
65
-
66
-
67
- def enq_bak(item,hint=nil)
68
- # Log.debug "--- #{self.class}#enq #{item.inspect}"
69
- th = nil
135
+ # enq
136
+ def enq(item)
137
+ Log.debug "--- TQ#enq #{item.name}"
70
138
  if @halt
71
- if th = @reservation[item]
72
- @reserved_q[th] = item
73
- else
74
- enq_impl(item,hint)
75
- end
139
+ enq_body(item)
76
140
  else
77
141
  @mutex.synchronize do
78
- if th = @reservation[item]
79
- @reserved_q[th] = item
80
- else
81
- enq_impl(item,hint)
82
- @cv.signal
83
- end
142
+ enq_body(item)
143
+ @cv.signal(item.suggest_location)
84
144
  end
85
145
  end
86
146
  @reserved_q.keys.each{|th|
@@ -89,13 +149,25 @@ module Pwrake
89
149
  }
90
150
  end
91
151
 
92
- def enq_impl(item,hint)
93
- @q.push(item) # FIFO Queue
152
+ def enq_body(item)
153
+ if th = @reservation[item]
154
+ @reserved_q[th] = item
155
+ else
156
+ enq_impl(item)
157
+ end
94
158
  end
95
159
 
160
+ def enq_impl(item)
161
+ if item.prior?
162
+ @q_prior.push(item)
163
+ else
164
+ @q_later.push(item)
165
+ end
166
+ end
96
167
 
168
+
169
+ # deq
97
170
  def deq(hint=nil)
98
- # Log.debug "--- #{self.class}#deq #{self.inspect}"
99
171
  n = 0
100
172
  loop do
101
173
  @mutex.synchronize do
@@ -104,7 +176,7 @@ module Pwrake
104
176
  return false
105
177
 
106
178
  elsif @halt
107
- Log.debug "--- halt in #{self.class}#deq @q=#{@q.inspect}"
179
+ Log.debug "--- halt in TQ#deq @q=#{@q.inspect}"
108
180
  @cv.wait(@mutex)
109
181
  n = 0
110
182
 
@@ -113,43 +185,47 @@ module Pwrake
113
185
  return item
114
186
 
115
187
  elsif empty? # no item in queue
116
- Log.debug "--- empty=true in #{self.class}#deq @finished=#{@finished.inspect}"
188
+ #Log.debug "--- empty=true in #{self.class}#deq @finished=#{@finished.inspect}"
117
189
  if @finished
118
- @cv.signal
190
+ @cv.signal
119
191
  return false
120
192
  end
121
- Log.debug "--- waiting in #{self.class}#deq @finished=#{@finished.inspect}"
193
+ #Log.debug "--- waiting in #{self.class}#deq @finished=#{@finished.inspect}"
122
194
  @cv.wait(@mutex)
123
195
  n = 0
124
196
 
125
197
  else
126
198
  if t = deq_impl(hint,n)
127
- Log.debug "--- #{self.class}#deq #{t.inspect}"
199
+ Log.debug "--- TQ#deq #{t.inspect}"
128
200
  return t
129
201
  end
202
+ #@cv.signal([hint])
130
203
  n += 1
131
204
  end
132
205
  end
206
+ #Thread.pass
133
207
  end
134
208
  end
135
209
 
136
210
  def deq_impl(hint,n)
137
- @q.shift # FIFO Queue
211
+ Log.debug "--- TQ#deq_impl #{@q.inspect}"
212
+ @q_prior.shift || @q_later.shift
138
213
  end
139
214
 
140
215
  def clear
141
- @q.clear
216
+ @q_prior.clear
217
+ @q_later.clear
142
218
  @reserved_q.clear
143
219
  end
144
220
 
145
221
  def empty?
146
- @q.empty? && @reserved_q.empty?
222
+ @q_prior.empty? && @q_later.empty? && @reserved_q.empty?
147
223
  end
148
224
 
149
225
  def finish
150
- Log.debug "--- #{self.class}#finish"
226
+ Log.debug "--- TQ#finish"
151
227
  @finished = true
152
- @cv.signal
228
+ @cv.broadcast
153
229
  end
154
230
 
155
231
  def stop
@@ -163,6 +239,10 @@ module Pwrake
163
239
  @th_end.push(th)
164
240
  @cv.broadcast
165
241
  end
166
- end
167
242
 
243
+ def after_check(tasks)
244
+ # implimented at subclass
245
+ end
246
+
247
+ end
168
248
  end
@@ -1,3 +1,3 @@
1
1
  module Pwrake
2
- VERSION = "0.9.5"
2
+ VERSION = "0.9.6"
3
3
  end
data/spec/004/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
1
  A = 4.times.map do |i|
2
- file "A#{i}" do |t|
2
+ task "A#{i}" do |t|
3
3
  sh "sleep 1"
4
4
  end.name
5
5
  end
@@ -1,2 +1,3 @@
1
1
  PROFILE : true
2
2
  GNU_TIME : true
3
+ #TASKLOG : true
data/spec/011/Rakefile ADDED
@@ -0,0 +1,15 @@
1
+ require "rake/clean"
2
+
3
+ hoge = %w[hoge1 hoge2]
4
+ CLEAN.include hoge
5
+ CLEAN.include "*._fail_"
6
+
7
+ task :default => hoge
8
+
9
+ file "hoge1" do
10
+ sh "echo hoge1>hoge1"
11
+ end
12
+
13
+ file "hoge2" do
14
+ sh "echo hoge2>hoge2; ls hogehoge"
15
+ end
data/spec/helper.rb CHANGED
@@ -69,11 +69,15 @@ class Helper
69
69
  while l = f.gets
70
70
  l = $1 if /^([^#]*)#/ =~ l
71
71
  host, ncore, group = l.split
72
- if host
72
+ case host
73
+ when /^localhost(\.localdomain)?$/
74
+ host = `hostname`.chomp if ssh
75
+ when nil
76
+ else
73
77
  host = `ssh #{host} hostname`.chomp if ssh
74
- ncore = (ncore || 1).to_i
75
- cores.concat( [host] * ncore )
76
78
  end
79
+ ncore = (ncore || 1).to_i
80
+ cores.concat( [host] * ncore )
77
81
  end
78
82
  end
79
83
  cores