scout-gear 7.2.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.vimproject +51 -6
  3. data/VERSION +1 -1
  4. data/bin/scout +6 -3
  5. data/lib/rbbt-scout.rb +1 -0
  6. data/lib/scout/cmd.rb +1 -1
  7. data/lib/scout/concurrent_stream.rb +33 -29
  8. data/lib/scout/config.rb +1 -1
  9. data/lib/scout/exceptions.rb +1 -0
  10. data/lib/scout/log/color.rb +4 -2
  11. data/lib/scout/log/progress/report.rb +1 -1
  12. data/lib/scout/log/progress/util.rb +71 -2
  13. data/lib/scout/log/progress.rb +1 -1
  14. data/lib/scout/log/trap.rb +107 -0
  15. data/lib/scout/log.rb +56 -21
  16. data/lib/scout/meta_extension.rb +13 -6
  17. data/lib/scout/misc/digest.rb +1 -1
  18. data/lib/scout/misc/format.rb +12 -0
  19. data/lib/scout/misc/helper.rb +31 -0
  20. data/lib/scout/misc/insist.rb +1 -1
  21. data/lib/scout/misc/monitor.rb +12 -1
  22. data/lib/scout/misc/system.rb +10 -0
  23. data/lib/scout/misc.rb +1 -0
  24. data/lib/scout/named_array.rb +65 -3
  25. data/lib/scout/open/lock/lockfile.rb +587 -0
  26. data/lib/scout/open/lock.rb +28 -2
  27. data/lib/scout/open/remote.rb +4 -0
  28. data/lib/scout/open/stream.rb +111 -42
  29. data/lib/scout/open/util.rb +13 -3
  30. data/lib/scout/path/find.rb +9 -1
  31. data/lib/scout/path/util.rb +35 -0
  32. data/lib/scout/persist/serialize.rb +18 -5
  33. data/lib/scout/persist.rb +60 -30
  34. data/lib/scout/resource/path.rb +53 -0
  35. data/lib/scout/resource/produce.rb +0 -8
  36. data/lib/scout/resource/util.rb +2 -1
  37. data/lib/scout/semaphore.rb +8 -1
  38. data/lib/scout/tmpfile.rb +7 -8
  39. data/lib/scout/tsv/attach.rb +177 -0
  40. data/lib/scout/tsv/change_id.rb +40 -0
  41. data/lib/scout/tsv/dumper.rb +85 -54
  42. data/lib/scout/tsv/index.rb +188 -20
  43. data/lib/scout/tsv/open.rb +182 -0
  44. data/lib/scout/tsv/parser.rb +200 -118
  45. data/lib/scout/tsv/path.rb +5 -6
  46. data/lib/scout/tsv/persist/adapter.rb +26 -37
  47. data/lib/scout/tsv/persist/fix_width_table.rb +327 -0
  48. data/lib/scout/tsv/persist/serialize.rb +117 -0
  49. data/lib/scout/tsv/persist/tokyocabinet.rb +6 -3
  50. data/lib/scout/tsv/persist.rb +4 -2
  51. data/lib/scout/tsv/transformer.rb +141 -0
  52. data/lib/scout/tsv/traverse.rb +136 -37
  53. data/lib/scout/tsv/util/filter.rb +312 -0
  54. data/lib/scout/tsv/util/process.rb +73 -0
  55. data/lib/scout/tsv/util/reorder.rb +81 -0
  56. data/lib/scout/tsv/util/select.rb +265 -0
  57. data/lib/scout/tsv/util/unzip.rb +86 -0
  58. data/lib/scout/tsv/util.rb +126 -19
  59. data/lib/scout/tsv.rb +28 -5
  60. data/lib/scout/work_queue/socket.rb +6 -1
  61. data/lib/scout/work_queue/worker.rb +5 -2
  62. data/lib/scout/work_queue.rb +15 -8
  63. data/lib/scout/workflow/definition.rb +29 -2
  64. data/lib/scout/workflow/step/dependencies.rb +24 -4
  65. data/lib/scout/workflow/step/info.rb +40 -5
  66. data/lib/scout/workflow/step/progress.rb +14 -0
  67. data/lib/scout/workflow/step/provenance.rb +8 -7
  68. data/lib/scout/workflow/step/status.rb +45 -0
  69. data/lib/scout/workflow/step.rb +104 -33
  70. data/lib/scout/workflow/task/inputs.rb +14 -20
  71. data/lib/scout/workflow/task.rb +86 -47
  72. data/lib/scout/workflow/usage.rb +10 -6
  73. data/scout-gear.gemspec +30 -3
  74. data/scout_commands/workflow/task +37 -9
  75. data/scout_commands/workflow/task_old +2 -2
  76. data/test/scout/open/test_stream.rb +61 -59
  77. data/test/scout/path/test_find.rb +10 -1
  78. data/test/scout/resource/test_produce.rb +15 -0
  79. data/test/scout/test_meta_extension.rb +25 -0
  80. data/test/scout/test_named_array.rb +18 -0
  81. data/test/scout/test_persist.rb +67 -0
  82. data/test/scout/test_tmpfile.rb +1 -1
  83. data/test/scout/test_tsv.rb +222 -3
  84. data/test/scout/test_work_queue.rb +21 -18
  85. data/test/scout/tsv/persist/test_adapter.rb +11 -1
  86. data/test/scout/tsv/persist/test_fix_width_table.rb +134 -0
  87. data/test/scout/tsv/persist/test_tokyocabinet.rb +29 -1
  88. data/test/scout/tsv/test_attach.rb +227 -0
  89. data/test/scout/tsv/test_change_id.rb +98 -0
  90. data/test/scout/tsv/test_dumper.rb +1 -1
  91. data/test/scout/tsv/test_index.rb +127 -3
  92. data/test/scout/tsv/test_open.rb +167 -0
  93. data/test/scout/tsv/test_parser.rb +45 -3
  94. data/test/scout/tsv/test_persist.rb +9 -0
  95. data/test/scout/tsv/test_transformer.rb +108 -0
  96. data/test/scout/tsv/test_traverse.rb +195 -3
  97. data/test/scout/tsv/test_util.rb +24 -0
  98. data/test/scout/tsv/util/test_filter.rb +188 -0
  99. data/test/scout/tsv/util/test_process.rb +47 -0
  100. data/test/scout/tsv/util/test_reorder.rb +94 -0
  101. data/test/scout/tsv/util/test_select.rb +58 -0
  102. data/test/scout/tsv/util/test_unzip.rb +112 -0
  103. data/test/scout/work_queue/test_socket.rb +0 -1
  104. data/test/scout/work_queue/test_worker.rb +63 -6
  105. data/test/scout/workflow/step/test_load.rb +3 -3
  106. data/test/scout/workflow/step/test_status.rb +31 -0
  107. data/test/scout/workflow/task/test_inputs.rb +14 -14
  108. data/test/scout/workflow/test_step.rb +13 -13
  109. data/test/scout/workflow/test_task.rb +168 -32
  110. data/test/scout/workflow/test_usage.rb +33 -6
  111. data/test/test_helper.rb +3 -1
  112. metadata +29 -2
@@ -54,11 +54,10 @@ module Open
54
54
 
55
55
  into_close = false unless into.respond_to? :close
56
56
 
57
- begin
58
- while c = io.readpartial(BLOCK_SIZE)
59
- into << c if into
60
- end
61
- rescue EOFError
57
+ while c = io.read(BLOCK_SIZE)
58
+ into << c if into
59
+ last_c = c if c
60
+ break if io.closed?
62
61
  end
63
62
 
64
63
  io.join if io.respond_to? :join
@@ -67,13 +66,15 @@ module Open
67
66
  into.close if into and into_close and not into.closed?
68
67
  block.call if block_given?
69
68
 
70
- c
69
+ last_c
71
70
  rescue Aborted
71
+ Thread.current["exception"] = true
72
72
  Log.low "Consume stream Aborted #{Log.fingerprint io} into #{into_path || into}"
73
73
  io.abort $! if io.respond_to? :abort
74
74
  into.close if into.respond_to?(:closed?) && ! into.closed?
75
75
  FileUtils.rm into_path if into_path and File.exist?(into_path)
76
76
  rescue Exception
77
+ Thread.current["exception"] = true
77
78
  Log.low "Consume stream Exception reading #{Log.fingerprint io} into #{into_path || into} - #{$!.message}"
78
79
  exception = (io.respond_to?(:stream_exception) && io.stream_exception) ? io.stream_exception : $!
79
80
  io.abort exception if io.respond_to? :abort
@@ -111,7 +112,6 @@ module Open
111
112
  FileUtils.mkdir_p File.dirname(tmp_path) unless File.directory?(File.dirname(tmp_path))
112
113
  FileUtils.rm_f tmp_path if File.exist? tmp_path
113
114
  begin
114
-
115
115
  case
116
116
  when block_given?
117
117
  File.open(tmp_path, 'wb', &block)
@@ -119,13 +119,10 @@ module Open
119
119
  File.open(tmp_path, 'wb') do |f| f.write content end
120
120
  when (IO === content or StringIO === content or File === content)
121
121
  Open.write(tmp_path) do |f|
122
- #f.sync = true
123
- begin
124
- while block = content.readpartial(BLOCK_SIZE)
125
- f.write block
126
- end
127
- rescue EOFError
128
- end
122
+ while block = content.read(BLOCK_SIZE)
123
+ f.write block
124
+ break if content.closed?
125
+ end
129
126
  end
130
127
  else
131
128
  File.open(tmp_path, 'wb') do |f| end
@@ -143,14 +140,15 @@ module Open
143
140
  content.join if content.respond_to?(:join) and not Path === content and not (content.respond_to?(:joined?) && content.joined?)
144
141
 
145
142
  Open.notify_write(path)
143
+ Log.debug "Done sensible write: [#{Process.pid}] -- #{ path }"
146
144
  rescue Aborted
147
- Log.low "Aborted sensible_write -- #{ Log.reset << Log.color(:blue, path) }"
145
+ Log.low "Aborted sensible_write -- #{ Log.reset << path }"
148
146
  content.abort if content.respond_to? :abort
149
147
  Open.rm path if File.exist? path
150
148
  rescue Exception
151
149
  exception = (AbortedStream === content and content.exception) ? content.exception : $!
152
- Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ Log.color :blue, path }"
153
- content.abort if content.respond_to? :abort
150
+ Log.low "Exception in sensible_write: [#{Process.pid}] #{exception.message} -- #{ path }"
151
+ content.abort(exception) if content.respond_to? :abort
154
152
  Open.rm path if File.exist? path
155
153
  raise exception
156
154
  rescue
@@ -191,7 +189,7 @@ module Open
191
189
  FileUtils.rm path if erase && File.exist?(path)
192
190
  end
193
191
  end
194
-
192
+
195
193
  def self.release_pipes(*pipes)
196
194
  PIPE_MUTEX.synchronize do
197
195
  pipes.flatten.each do |pipe|
@@ -243,7 +241,7 @@ module Open
243
241
  begin
244
242
  Thread.current.report_on_exception = false
245
243
  Thread.current["name"] = "Pipe input #{Log.fingerprint sin} => #{Log.fingerprint sout}"
246
-
244
+
247
245
  yield sin
248
246
 
249
247
  sin.close if close and not sin.closed? and not sin.aborted?
@@ -290,31 +288,36 @@ module Open
290
288
  Thread.current["name"] = "Splitter #{Log.fingerprint stream}"
291
289
 
292
290
  skip = [false] * num
293
- begin
294
- while block = stream.readpartial(BLOCK_SIZE)
295
-
296
- in_pipes.each_with_index do |sin,i|
297
- begin
298
- sin.write block
299
- rescue IOError
300
- Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
301
- skip[i] = true
302
- rescue
303
- Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
304
- raise $!
305
- end unless skip[i]
306
- end
291
+ while block = stream.read(BLOCK_SIZE)
292
+
293
+ in_pipes.each_with_index do |sin,i|
294
+ begin
295
+ sin.write block
296
+ rescue IOError
297
+ Log.warn("Tee stream #{i} #{Log.fingerprint stream} IOError: #{$!.message} (#{Log.fingerprint sin})");
298
+ skip[i] = true
299
+ rescue
300
+ Log.warn("Tee stream #{i} #{Log.fingerprint stream} Exception: #{$!.message} (#{Log.fingerprint sin})");
301
+ raise $!
302
+ end unless skip[i]
307
303
  end
308
- rescue IOError
304
+ break if stream.closed?
309
305
  end
310
306
 
311
307
  stream.join if stream.respond_to? :join
312
308
  stream.close unless stream.closed?
313
309
  in_pipes.first.close unless in_pipes.first.closed?
314
310
  rescue Aborted, Interrupt
315
- stream.abort if stream.respond_to? :abort
316
- out_pipes.each do |sout|
317
- sout.abort if sout.respond_to? :abort
311
+ stream.abort if stream.respond_to?(:abort) && ! stream.aborted?
312
+ out_pipes.reverse.each do |sout|
313
+ sout.threads.delete(Thread.current)
314
+ begin
315
+ sout.abort($!) if sout.respond_to?(:abort) && ! sout.aborted?
316
+ rescue
317
+ end
318
+ end
319
+ in_pipes.each do |sin|
320
+ sin.close unless sin.closed?
318
321
  end
319
322
  Log.low "Tee aborting #{Log.fingerprint stream}"
320
323
  raise $!
@@ -333,12 +336,14 @@ module Open
333
336
  end
334
337
  Log.low "Tee exception #{Log.fingerprint stream}"
335
338
  rescue
336
- Log.exception $!
337
339
  ensure
338
- in_pipes.each do |sin|
339
- sin.close unless sin.closed?
340
+ begin
341
+ in_pipes.each do |sin|
342
+ sin.close unless sin.closed?
343
+ end
344
+ ensure
345
+ raise $!
340
346
  end
341
- raise $!
342
347
  end
343
348
  end
344
349
  end
@@ -397,7 +402,7 @@ module Open
397
402
  end
398
403
  str
399
404
  end
400
-
405
+
401
406
  def self.sort_stream(stream, header_hash = "#", cmd_args = "-u")
402
407
  Open.open_pipe do |sin|
403
408
  line = stream.gets
@@ -431,5 +436,69 @@ module Open
431
436
  end
432
437
  end
433
438
 
439
+ def self.process_stream(s)
440
+ begin
441
+ yield s
442
+ s.close if s.respond_to?(:close) && ! s.closed?
443
+ s.join if s.respond_to?(:join)
444
+ rescue
445
+ s.abort($!) if s.respond_to? :abort
446
+ raise $!
447
+ end
448
+ end
449
+
450
+
451
+ def self.collapse_stream(s, line: nil, sep: "\t", header: nil, &block)
452
+ sep ||= "\t"
453
+ Open.open_pipe do |sin|
454
+ sin.puts header if header
455
+ process_stream(s) do |s|
456
+ line ||= s.gets
457
+
458
+ current_parts = []
459
+ while line
460
+ key, *parts = line.chomp.split(sep, -1)
461
+ case
462
+ when key.nil?
463
+ when current_parts.nil?
464
+ current_parts = parts
465
+ current_key = key
466
+ when current_key == key
467
+ parts.each_with_index do |part,i|
468
+ if current_parts[i].nil?
469
+ current_parts[i] = "|" << part
470
+ else
471
+ current_parts[i] = current_parts[i] << "|" << part
472
+ end
473
+ end
474
+
475
+ (parts.length..current_parts.length-1).to_a.each do |pos|
476
+ current_parts[pos] = current_parts[pos] << "|" << ""
477
+ end
478
+ when current_key.nil?
479
+ current_key = key
480
+ current_parts = parts
481
+ when current_key != key
482
+ if block_given?
483
+ res = block.call(current_parts)
484
+ sin.puts [current_key, res] * sep
485
+ else
486
+ sin.puts [current_key, current_parts].flatten * sep
487
+ end
488
+ current_key = key
489
+ current_parts = parts
490
+ end
491
+ line = s.gets
492
+ end
493
+
494
+ if block_given?
495
+ res = block.call(current_parts)
496
+ sin.puts [current_key, res] * sep
497
+ else
498
+ sin.puts [current_key, current_parts].flatten * sep
499
+ end unless current_key.nil?
500
+ end
501
+ end
502
+ end
434
503
 
435
504
  end
@@ -94,6 +94,11 @@ module Open
94
94
  File.symlink?(path) && ! File.exist?(File.readlink(path))
95
95
  end
96
96
 
97
+ def self.directory?(file)
98
+ file = file.find if Path === file
99
+ File.directory?(file)
100
+ end
101
+
97
102
  def self.exists?(file)
98
103
  file = file.find if Path === file
99
104
  File.exist?(file)
@@ -111,7 +116,7 @@ module Open
111
116
  end
112
117
 
113
118
  def self.rm(file)
114
- FileUtils.rm(file) if File.exist?(file) or Open.broken_link?(file)
119
+ FileUtils.rm(file) if File.exist?(file) || Open.broken_link?(file)
115
120
  end
116
121
 
117
122
  def self.rm_rf(file)
@@ -155,7 +160,7 @@ module Open
155
160
  begin
156
161
  if File.symlink?(file) || File.stat(file).nlink > 1
157
162
  if File.exist?(file + '.info') && defined?(Step)
158
- done = Step::INFO_SERIALIZER.load(Open.open(file + '.info'))[:done]
163
+ done = Persist.load(file + '.info', Step::SERIALIZER)[:done]
159
164
  return done if done
160
165
  end
161
166
 
@@ -173,7 +178,7 @@ module Open
173
178
  target = target.find if Path === target
174
179
 
175
180
  FileUtils.mkdir_p File.dirname(target) unless File.exist?(File.dirname(target))
176
- FileUtils.rm target if File.exist?(target)
181
+ FileUtils.rm_rf target if File.exist?(target)
177
182
  FileUtils.cp_r source, target
178
183
  end
179
184
 
@@ -222,4 +227,9 @@ module Open
222
227
  end
223
228
  nil
224
229
  end
230
+
231
+ def self.list(file)
232
+ file = file.produce_and_find if Path === file
233
+ Open.read(file).split("\n")
234
+ end
225
235
  end
@@ -10,8 +10,10 @@ module Path
10
10
  file =~ /(?:scout|rbbt)\/(?:.*\/)?path\.rb/ or
11
11
  file =~ /(?:scout|rbbt)\/(?:.*\/)?path\/(?:find|refactor|util)\.rb/ or
12
12
  file =~ /(?:scout|rbbt)\/persist.rb/ or
13
+ file =~ /scout\/resource\/produce.rb/ or
13
14
  file =~ /modules\/rbbt-util/
14
15
  end
16
+ return nil if file.nil?
15
17
  file = file.sub(/\.rb[^\w].*/,'.rb')
16
18
  end
17
19
 
@@ -38,7 +40,7 @@ module Path
38
40
  sub('{SUBPATH}', path._subpath).
39
41
  sub('{BASENAME}', File.basename(path)).
40
42
  sub('{PATH}', path).
41
- sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir).
43
+ sub('{LIBDIR}', path.libdir || (path.pkgdir.respond_to?(:libdir) && path.pkgdir.libdir) || Path.caller_lib_dir || "NOLIBDIR").
42
44
  sub('{MAPNAME}', map_name.to_s).
43
45
  sub('{REMOVE}/', '').
44
46
  sub('{REMOVE}', '').gsub(/\/+/,'/')
@@ -188,4 +190,10 @@ module Path
188
190
  .select{|file| file.exist? }.uniq
189
191
  end
190
192
 
193
+ def find_with_extension(extension, *args)
194
+ found = self.find(*args)
195
+ return found if found.exists?
196
+ found_with_extension = self.set_extension(extension).find
197
+ found_with_extension.exists? ? found_with_extension : found
198
+ end
191
199
  end
@@ -12,6 +12,23 @@ module Path
12
12
  return false
13
13
  end
14
14
 
15
+ def self.sanitize_filename(filename, length = 254)
16
+ if filename.length > length
17
+ if filename =~ /(\..{2,9})$/
18
+ extension = $1
19
+ else
20
+ extension = ''
21
+ end
22
+
23
+ post_fix = "--#{filename.length}@#{length}_#{Misc.digest(filename)[0..4]}" + extension
24
+
25
+ filename = filename[0..(length - post_fix.length - 1)] << post_fix
26
+ else
27
+ filename
28
+ end
29
+ filename
30
+ end
31
+
15
32
  def directory?
16
33
  return nil unless self.exist?
17
34
  File.directory?(self.find)
@@ -64,4 +81,22 @@ module Path
64
81
  def set_extension(extension)
65
82
  self.annotate(self + ".#{extension}")
66
83
  end
84
+
85
+ # Is 'file' newer than 'path'? return non-true if path is newer than file
86
+ def self.newer?(path, file, by_link = false)
87
+ return true if not Open.exists?(file)
88
+ path = path.find if Path === path
89
+ file = file.find if Path === file
90
+ if by_link
91
+ patht = File.exist?(path) ? File.lstat(path).mtime : nil
92
+ filet = File.exist?(file) ? File.lstat(file).mtime : nil
93
+ else
94
+ patht = Open.mtime(path)
95
+ filet = Open.mtime(file)
96
+ end
97
+ return true if patht.nil? || filet.nil?
98
+ diff = patht - filet
99
+ return diff if diff < 0
100
+ return false
101
+ end
67
102
  end
@@ -1,5 +1,6 @@
1
1
  require_relative '../open'
2
2
  require_relative 'open'
3
+ require 'set'
3
4
 
4
5
  module Persist
5
6
  TRUE_STRINGS = Set.new ["true", "True", "TRUE", "t", "T", "1", "yes", "Yes", "YES", "y", "Y", "ON", "on"] unless defined? TRUE_STRINGS
@@ -19,7 +20,7 @@ module Persist
19
20
  type = type.to_sym if String === type
20
21
  type = SERIALIZER if type == :serializer
21
22
  case type
22
- when nil, :string, :integer, :float, :boolean, :file, :path
23
+ when nil, :string, :integer, :float, :boolean, :file, :path, :select, :folder
23
24
  if IO === content || StringIO === content
24
25
  content.read
25
26
  else
@@ -46,8 +47,9 @@ module Persist
46
47
  def self.deserialize(serialized, type)
47
48
  type = type.to_sym if String === type
48
49
  type = SERIALIZER if type == :serializer
50
+
49
51
  case type
50
- when nil, :string, :file, :stream
52
+ when nil, :string, :file, :stream, :select, :folder
51
53
  serialized
52
54
  when :path
53
55
  Path.setup(serialized)
@@ -99,9 +101,18 @@ module Persist
99
101
  return save_drivers[type].call(file, content)
100
102
  end
101
103
  end
102
- serialized = serialize(content, type)
103
- Open.sensible_write(file, serialized, :force => true)
104
- return nil
104
+
105
+ if type == :binary
106
+ content.force_encoding("ASCII-8BIT") if content.respond_to? :force_encoding
107
+ Open.open(path, :mode => 'wb') do |f|
108
+ f.puts content
109
+ end
110
+ content
111
+ else
112
+ serialized = serialize(content, type)
113
+ Open.sensible_write(file, serialized, :force => true)
114
+ return nil
115
+ end
105
116
  end
106
117
 
107
118
  def self.load(file, type = :serializer)
@@ -118,6 +129,8 @@ module Persist
118
129
  end
119
130
 
120
131
  case type
132
+ when :binary
133
+ Open.read(file, :mode => 'rb')
121
134
  when :yaml
122
135
  Open.yaml(file)
123
136
  when :json
data/lib/scout/persist.rb CHANGED
@@ -14,61 +14,91 @@ module Persist
14
14
 
15
15
  attr_writer :lock_dir
16
16
  def lock_dir
17
- @lock_dir ||= Path.setup("var/cache/persist_locks")
17
+ @lock_dir ||= Path.setup("tmp/persist_locks").find
18
18
  end
19
19
  end
20
20
 
21
21
  def self.persistence_path(name, options = {})
22
22
  options = IndiferentHash.add_defaults options, :dir => Persist.cache_dir
23
23
  other_options = IndiferentHash.pull_keys options, :other
24
- TmpFile.tmp_for_file(name, options, other_options)
24
+ name = name.filename if name.respond_to?(:filename) && name.filename
25
+ persist_options = {}
26
+ TmpFile.tmp_for_file(name, options.merge(persist_options), other_options)
25
27
  end
26
28
 
29
+ MEMORY_CACHE = {}
30
+ CONNECTIONS = {}
27
31
  def self.persist(name, type = :serializer, options = {}, &block)
28
32
  persist_options = IndiferentHash.pull_keys options, :persist
29
33
  return yield if FalseClass === persist_options[:persist]
30
34
  file = persist_options[:path] || options[:path] || persistence_path(name, options)
31
35
 
36
+ if type == :memory
37
+ repo = options[:memory] || options[:repo] || MEMORY_CACHE
38
+ repo[file] ||= yield
39
+ return repo[file]
40
+ end
41
+
32
42
  update = options[:update] || persist_options[:update]
33
43
  update = Open.mtime(update) if Path === update
34
44
  update = Open.mtime(file) >= update ? false : true if Time === update
35
45
 
36
- if Open.exist?(file) && ! update
37
- Persist.load(file, type)
38
- else
39
- return yield(file) if block.arity == 1
40
- res = yield
41
- begin
42
- Open.rm(file)
46
+ lockfile = persist_options[:lockfile] || options[:lockfile] || Persist.persistence_path(file + '.persist', {:dir => Persist.lock_dir})
47
+
48
+ Open.lock lockfile do |lock|
49
+ if Open.exist?(file) && ! update
50
+ Persist.load(file, type)
51
+ else
52
+ begin
53
+ file = file.find if Path === file
54
+ return yield(file) if block.arity == 1
55
+ res = yield
56
+
57
+ if res.nil?
58
+ return Persist.load(file, type)
59
+ end
60
+
61
+ Open.rm(file)
43
62
 
44
- if IO === res || StringIO === res
45
- tee_copies = options[:tee_copies] || 1
46
- main, *copies = Open.tee_stream_thread_multiple res, tee_copies + 1
47
- t = Thread.new do
48
- Thread.current.report_on_exception = false
49
- Thread.current["name"] = "file saver: " + file
50
- Open.sensible_write(file, main)
63
+ if IO === res || StringIO === res
64
+ tee_copies = options[:tee_copies] || 1
65
+ main, *copies = Open.tee_stream_thread_multiple res, tee_copies + 1
66
+ main.lock = lock
67
+ t = Thread.new do
68
+ Thread.current.report_on_exception = false
69
+ Thread.current["name"] = "file saver: " + file
70
+ Open.sensible_write(file, main)
71
+ end
72
+ Thread.pass until t["name"]
73
+ copies.each_with_index do |copy,i|
74
+ next_stream = copies[i+1] if copies.length > i
75
+ ConcurrentStream.setup copy, :threads => t, :filename => file, :autojoin => true, :next => next_stream
76
+ end
77
+ res = copies.first
78
+ raise KeepLocked.new(res)
79
+ else
80
+ pres = Persist.save(res, file, type)
81
+ res = pres unless pres.nil?
51
82
  end
52
- Thread.pass until t["name"]
53
- copies.each_with_index do |copy,i|
54
- next_stream = copies[i+1] if copies.length > i
55
- ConcurrentStream.setup copy, :threads => t, :filename => file, :autojoin => true, :next => next_stream
83
+ rescue
84
+ Thread.handle_interrupt(Exception => :never) do
85
+ if Open.exist?(file)
86
+ Log.debug "Failed persistence #{file} - erasing"
87
+ Open.rm file
88
+ else
89
+ Log.debug "Failed persistence #{file}"
90
+ end
56
91
  end
57
- res = copies.first
58
- else
59
- pres = Persist.save(res, file, type)
60
- res = pres unless pres.nil?
92
+ raise $! unless options[:canfail]
61
93
  end
62
- rescue
63
- raise $! unless options[:canfail]
64
- Log.debug "Could not persist #{type} on #{file}"
94
+ res
65
95
  end
66
- res
67
96
  end
68
97
  end
69
98
 
70
- def self.memory(name, *args, &block)
71
- self.persist(name, :memory, *args, &block)
99
+ def self.memory(name, options = {}, &block)
100
+ options[:persist_path] ||= options[:path] ||= [name, options[:key]].compact * ":"
101
+ self.persist(name, :memory, options, &block)
72
102
  end
73
103
 
74
104
  end
@@ -1,4 +1,47 @@
1
1
  module Path
2
+ def produce(force = false)
3
+ return self if ! force && (Open.exist?(self) || @produced)
4
+ begin
5
+ if Resource === self.pkgdir
6
+ self.pkgdir.produce self
7
+ else
8
+ false
9
+ end
10
+ rescue ResourceNotFound
11
+ false
12
+ rescue
13
+ message = $!.message
14
+ message = "No exception message" if message.nil? || message.empty?
15
+ Log.warn "Error producing #{self}: #{message}"
16
+ false
17
+ ensure
18
+ @produced = true
19
+ end
20
+ end
21
+
22
+ def produce_with_extension(extension, *args)
23
+ begin
24
+ self.produce(*args)
25
+ rescue Exception
26
+ exception = $!
27
+ begin
28
+ self.set_extension(extension).produce(*args)
29
+ rescue Exception
30
+ raise exception
31
+ end
32
+ end
33
+ end
34
+
35
+ def produce_and_find(extension = nil, *args)
36
+ if extension
37
+ found = find_with_extension(extension, *args)
38
+ found.exists? ? found : produce_with_extension(extension, *args)
39
+ else
40
+ found = find
41
+ found.exists? ? found : produce(*args)
42
+ end
43
+ end
44
+
2
45
  def relocate
3
46
  return self if Open.exists?(self)
4
47
  Resource.relocate(self)
@@ -17,4 +60,14 @@ module Path
17
60
  def write(*args, &block)
18
61
  Open.write(self.find, *args, &block)
19
62
  end
63
+
64
+ def list
65
+ found = produce_and_find('list')
66
+ Open.list(found)
67
+ end
68
+
69
+ def exists?
70
+ return true if Open.exists?(self.find)
71
+ self.produce
72
+ end
20
73
  end
@@ -149,11 +149,3 @@ module Resource
149
149
  end
150
150
 
151
151
  end
152
-
153
- module Path
154
- def produce(force = false)
155
- return self if ! force && Open.exist?(self)
156
- self.pkgdir.produce self if Resource === self.pkgdir
157
- return self
158
- end
159
- end
@@ -1,7 +1,8 @@
1
1
  module Resource
2
2
  def identify(path)
3
3
  return path unless path.start_with?("/")
4
- path_maps = path.path_maps || self.path_maps || Path.path_maps
4
+ path_maps = path.path_maps if Path === path
5
+ path_maps ||= self.path_maps || Path.path_maps
5
6
  path = File.expand_path(path)
6
7
  path += "/" if File.directory?(path)
7
8
 
@@ -37,7 +37,13 @@ if continue
37
37
  int ret;
38
38
  sem_t* sem;
39
39
  sem = sem_open(name, 0);
40
+ if (sem == SEM_FAILED){
41
+ return(errno);
42
+ }
40
43
  ret = sem_wait(sem);
44
+ if (ret == -1){
45
+ return(errno);
46
+ }
41
47
  sem_close(sem);
42
48
  return(ret);
43
49
  }
@@ -51,6 +57,7 @@ if continue
51
57
  sem_close(sem);
52
58
  }
53
59
  EOF
60
+
54
61
  end
55
62
 
56
63
  SEM_MUTEX = Mutex.new
@@ -66,7 +73,7 @@ if continue
66
73
 
67
74
  def self.with_semaphore(size, file = nil)
68
75
  if file.nil?
69
- file = "/" << Misc.digest(rand(1000000000000).to_s) if file.nil?
76
+ file = "/scout-" << Misc.digest(rand(100000000000).to_s)[0..10] if file.nil?
70
77
  else
71
78
  file = file.gsub('/', '_') if file
72
79
  end