rbbt-util 5.14.18 → 5.14.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 243728b311e7948c452e6de9e299e5938a3ebd24
4
- data.tar.gz: 8eb9ee8a10b1653c79465eab2c68f340a39ecc9f
3
+ metadata.gz: f5bc1786fca01c18645eeb743092710a25ebef1e
4
+ data.tar.gz: 7b4698982619547c6d37a6b0357f1937d33a7baa
5
5
  SHA512:
6
- metadata.gz: 46d41fe4394efa9c7ad329e8fa42d0fcd3ea6d2d72cd30a7d2b3f6d7fd8df61565f621ad339abc74d7662a5220df92d2de03beb46f0b5ded72d5a967e532f752
7
- data.tar.gz: 20566c536d6b4f4946feedea1e5ad956caf883d8772db394fc8217bbc9eae1bacecb9d5b74fdfde0d45cd94784b82f8ceed01ac3ed286edfa8e35dd3782a12c7
6
+ metadata.gz: fdf6ad7098498a63382450710dec248108f2956f8919ee72f63ee27fb1c9863eaedd449662ea709fce610c3735d6dc2eac37a3c58ad8c9451935ee32b8076ca1
7
+ data.tar.gz: 7d59b991703716459c7fec294b7acdffe8a55f33cd5ba989fc634d2e01a9be973ae092863f1aaeb661a16c662935c9ec858ecee98124c8aa4aa6995be25be743
@@ -40,4 +40,3 @@ $annotation_repo = Rbbt.var.sinatra.annotation_repo.find
40
40
  end
41
41
  end if Rbbt.etc.persist_properties.exists?
42
42
 
43
-
@@ -22,12 +22,12 @@ class KnowledgeBase
22
22
 
23
23
  attr_accessor :namespace, :dir, :indices, :registry, :format, :databases, :entity_options
24
24
  def initialize(dir, namespace = nil)
25
- @dir = Path.setup(dir).find
25
+ @dir = Path.setup(dir.dup).find
26
26
 
27
27
  @namespace = namespace
28
28
  @format = IndiferentHash.setup({})
29
29
 
30
- @registry = IndiferentHash.setup({})
30
+ @registry ||= IndiferentHash.setup({})
31
31
  @entity_options = IndiferentHash.setup({})
32
32
 
33
33
  @indices = IndiferentHash.setup({})
@@ -59,7 +59,7 @@ class KnowledgeBase
59
59
  end
60
60
  end
61
61
 
62
- def syndicate(kb, name)
62
+ def syndicate(name, kb)
63
63
  kb.all_databases.each do |database|
64
64
  db_name = [database, name] * "@"
65
65
  file, kb_options = kb.registry[database]
@@ -72,7 +72,7 @@ class KnowledgeBase
72
72
  end
73
73
 
74
74
  def all_databases
75
- @registry.keys
75
+ @registry.keys
76
76
  end
77
77
 
78
78
  def description(name)
@@ -117,43 +117,103 @@ class KnowledgeBase
117
117
  {:namespace => namespace, :format => @format}
118
118
  end
119
119
 
120
+ #def get_database(name, options = {})
121
+ # @databases[Misc.fingerprint([name, options])] ||= \
122
+ # begin
123
+ # Persist.memory("Database:" <<[name, self.dir] * "@") do
124
+ # options = Misc.add_defaults options, :persist_dir => dir.databases
125
+ # persist_options = Misc.pull_keys options, :persist
126
+
127
+ # file, registered_options = registry[name]
128
+ # options = open_options.merge(registered_options || {}).merge(options)
129
+ # raise "Repo #{ name } not found and not registered" if file.nil?
130
+
131
+ # Log.low "Opening database #{ name } from #{ Misc.fingerprint file }. #{options}"
132
+ # Association.open(file, options, persist_options).
133
+ # tap{|tsv| tsv.namespace = self.namespace}
134
+ # end
135
+ # end
136
+ #end
137
+
138
+
139
+ #def get_index(name, options = {})
140
+ # @indices[Misc.fingerprint([name, options])] ||= \
141
+ # begin
142
+ # Persist.memory("Index:" <<[name, self.dir] * "@") do
143
+ # options = Misc.add_defaults options, :persist_dir => dir.indices
144
+ # persist_options = Misc.pull_keys options, :persist
145
+
146
+ # file, registered_options = registry[name]
147
+ # options = open_options.merge(registered_options || {}).merge(options)
148
+ # raise "Repo #{ name } not found and not registered" if file.nil?
149
+
150
+ # Log.low "Opening index #{ name } from #{ Misc.fingerprint file }. #{options}"
151
+ # Association.index(file, options, persist_options).
152
+ # tap{|tsv| tsv.namespace = self.namespace}
153
+ # end
154
+ # end
155
+ #end
156
+
120
157
  def get_database(name, options = {})
121
- @databases[Misc.fingerprint([name, options])] ||= \
158
+ key = name.to_s + "_" + Misc.digest(Misc.fingerprint([name,options,format,namespace]))
159
+ @databases[key] ||=
122
160
  begin
123
- Persist.memory("Database:" <<[name, self.dir] * "@") do
124
- options = Misc.add_defaults options, :persist_dir => dir.databases
161
+ Persist.memory("Database:" << [key, dir] * "@") do
162
+ persist_file = dir.databases[key]
163
+ file, registered_options = registry[name]
164
+
165
+ options = Misc.add_defaults options, :persist_file => persist_file, :namespace => namespace, :format => format
166
+ options = Misc.add_defaults options, registered_options
167
+
125
168
  persist_options = Misc.pull_keys options, :persist
126
169
 
127
- file, registered_options = registry[name]
128
- options = open_options.merge(registered_options || {}).merge(options)
129
- raise "Repo #{ name } not found and not registered" if file.nil?
170
+ database = if persist_file.exists?
171
+ Log.low "Re-opening database #{ name } from #{ Misc.fingerprint persist_file }. #{options}"
172
+ Association.open(file, options, persist_options)
173
+ else
174
+ raise "Repo #{ name } not found and not registered" if file.nil?
175
+ Log.low "Opening database #{ name } from #{ Misc.fingerprint file }. #{options}"
176
+ Association.open(file, options, persist_options)
177
+ end
178
+
179
+ database.namespace = self.namespace
130
180
 
131
- Log.low "Opening database #{ name } from #{ Misc.fingerprint file }. #{options}"
132
- Association.open(file, options, persist_options).
133
- tap{|tsv| tsv.namespace = self.namespace}
181
+ database
134
182
  end
135
183
  end
136
184
  end
137
185
 
138
-
139
186
  def get_index(name, options = {})
140
- @indices[Misc.fingerprint([name, options])] ||= \
187
+ key = name.to_s + "_" + Misc.digest(Misc.fingerprint([name,options]))
188
+ @indices[key] ||=
141
189
  begin
142
- Persist.memory("Index:" <<[name, self.dir] * "@") do
143
- options = Misc.add_defaults options, :persist_dir => dir.indices
190
+ Persist.memory("Index:" << [key, dir] * "@") do
191
+ persist_file = dir.indices[key]
192
+ file, registered_options = registry[name]
193
+
194
+ options = Misc.add_defaults options, :persist_file => persist_file, :namespace => namespace, :format => format
195
+ options = Misc.add_defaults options, registered_options
196
+
144
197
  persist_options = Misc.pull_keys options, :persist
145
198
 
146
- file, registered_options = registry[name]
147
- options = open_options.merge(registered_options || {}).merge(options)
148
- raise "Repo #{ name } not found and not registered" if file.nil?
199
+ index = if persist_file.exists?
200
+ Log.low "Re-opening index #{ name } from #{ Misc.fingerprint persist_file }. #{options}"
201
+ Association.index(nil, options, persist_options)
202
+ else
203
+ options = Misc.add_defaults options, registered_options if registered_options
204
+ raise "Repo #{ name } not found and not registered" if file.nil?
205
+ Log.low "Opening index #{ name } from #{ Misc.fingerprint file }. #{options}"
206
+ Association.index(file, options, persist_options)
207
+ end
208
+
209
+ index.namespace = self.namespace
149
210
 
150
- Log.low "Opening index #{ name } from #{ Misc.fingerprint file }. #{options}"
151
- Association.index(file, options, persist_options).
152
- tap{|tsv| tsv.namespace = self.namespace}
211
+ index
153
212
  end
154
213
  end
155
214
  end
156
215
 
216
+
157
217
  #{{{ Add manual database
158
218
 
159
219
  def add_index(name, source_type, target_type, *fields)
@@ -292,6 +352,8 @@ class KnowledgeBase
292
352
 
293
353
  def subset(name, entities)
294
354
  entities = case entities
355
+ when :all
356
+ {:target => :all, :source => :all}
295
357
  when AnnotatedArray
296
358
  format = entities.format if entities.respond_to? :format
297
359
  format ||= entities.base_entity.to_s
@@ -319,7 +381,7 @@ class KnowledgeBase
319
381
  end
320
382
 
321
383
  def translate(entities, type)
322
- if format = @format[type] and format != entities.format
384
+ if format = @format[type] and (entities.respond_to? :format and format != entities.format)
323
385
  entities.to format
324
386
  else
325
387
  entities
@@ -34,12 +34,12 @@ module TSV
34
34
 
35
35
  new_values.flatten if type == :flat
36
36
 
37
- self[key] = current.concat new_values
37
+ self[key] = current + new_values
38
38
  else
39
39
  if type == :double
40
- self[key] = current.concat [[]] * fields.length
40
+ self[key] = current + [[]] * fields.length
41
41
  else
42
- self[key] = current.concat [nil] * fields.length
42
+ self[key] = current + [nil] * fields.length
43
43
  end
44
44
  end
45
45
  end
@@ -528,6 +528,16 @@ module TSV
528
528
  new
529
529
  end
530
530
 
531
+ def column_values(field, options = {})
532
+ all = []
533
+ through :key, field do |k,values|
534
+ values = Array === values ? values.flatten : [values]
535
+ all.concat value
536
+ end
537
+ prepare_entity(all, field, options = {})
538
+ end
539
+
540
+
531
541
  def process_key(&block)
532
542
  new = annotate({})
533
543
  through do |key, values|
@@ -334,9 +334,9 @@ module TSV
334
334
 
335
335
  def self.traverse_cpus(num, obj, options, &block)
336
336
  begin
337
- callback, cleanup, join = Misc.process_options options, :callback, :cleanup, :join
337
+ callback, cleanup, join, respawn = Misc.process_options options, :callback, :cleanup, :join, :respawn
338
338
 
339
- q = RbbtProcessQueue.new num, cleanup, join
339
+ q = RbbtProcessQueue.new num, cleanup, join, respawn
340
340
  q.callback &callback
341
341
  q.init &block
342
342
 
@@ -3,12 +3,13 @@ require 'rbbt/util/concurrency/processes/socket'
3
3
 
4
4
  class RbbtProcessQueue
5
5
 
6
- attr_accessor :num_processes, :processes, :queue, :process_monitor, :cleanup, :join
7
- def initialize(num_processes, cleanup = nil, join = nil)
6
+ attr_accessor :num_processes, :processes, :queue, :process_monitor, :cleanup, :join, :reswpan
7
+ def initialize(num_processes, cleanup = nil, join = nil, reswpan = nil)
8
8
  @num_processes = num_processes
9
9
  @processes = []
10
10
  @cleanup = cleanup
11
11
  @join = join
12
+ @respawn = reswpan
12
13
  @queue = RbbtProcessSocket.new
13
14
  end
14
15
 
@@ -48,7 +49,7 @@ class RbbtProcessQueue
48
49
 
49
50
  def init(&block)
50
51
  num_processes.times do |i|
51
- @processes << RbbtProcessQueueWorker.new(@queue, @callback_queue, @cleanup, &block)
52
+ @processes << RbbtProcessQueueWorker.new(@queue, @callback_queue, @cleanup, @respawn, &block)
52
53
  end
53
54
  @queue.close_read
54
55
 
@@ -2,46 +2,126 @@ require 'rbbt/util/concurrency/processes/socket'
2
2
  class RbbtProcessQueue
3
3
  class RbbtProcessQueueWorker
4
4
  attr_reader :pid, :queue, :callback_queue, :cleanup, :block
5
- def initialize(queue, callback_queue = nil, cleanup = nil, &block)
6
- @queue, @callback_queue, @cleanup, @block = queue, callback_queue, cleanup, block
7
5
 
8
- @pid = Process.fork do
9
- begin
10
- Misc.pre_fork
6
+ class Respawn < Exception; end
7
+
8
+ def run
9
+ begin
10
+ Signal.trap(:INT){
11
+ Kernel.exit! -1
12
+ }
13
+
14
+ @stop = false
15
+ Signal.trap(:USR1){
16
+ @stop = true
17
+ }
18
+
19
+ loop do
20
+ p = @queue.pop
21
+ next if p.nil?
22
+ raise p if Exception === p
23
+ raise p.first if Exception === p.first
24
+ res = @block.call *p
25
+ @callback_queue.push res if @callback_queue
26
+ raise Respawn if @stop
27
+ end
28
+ Kernel.exit! 0
29
+ rescue Respawn
30
+ Kernel.exit! 28
31
+ rescue ClosedStream
32
+ rescue Aborted, Interrupt
33
+ Log.warn "Worker #{Process.pid} aborted"
34
+ Kernel.exit! 0
35
+ rescue Exception
36
+ Log.exception $!
37
+ @callback_queue.push($!) if @callback_queue
38
+ Kernel.exit! -1
39
+ ensure
40
+ @callback_queue.close_write if @callback_queue
41
+ end
42
+ end
11
43
 
12
- @cleanup.call if @cleanup
13
- @queue.close_write
44
+ def run_with_respawn(multiplier = nil)
45
+ multiplier = case multiplier
46
+ when String
47
+ multiplier.to_s
48
+ when Fixnum
49
+ multiplier.to_i
50
+ else
51
+ 3
52
+ end
14
53
 
15
- if @callback_queue
16
- Misc.purge_pipes(@callback_queue.swrite)
17
- @callback_queue.close_read
18
- else
19
- Misc.purge_pipes
54
+ status = nil
55
+ begin
56
+ @current = Process.fork do
57
+ run
58
+ end
59
+ Log.warn "Worker #{Process.pid} started with #{@current}"
60
+
61
+ @monitor_thread = Thread.new do
62
+ begin
63
+ while true
64
+ current = Misc.memory_use(@current)
65
+ initial = Misc.memory_use(Process.pid)
66
+ if current > multiplier * initial
67
+ Process.kill "USR1", @current
68
+ end
69
+ sleep 1
70
+ end
71
+ rescue
72
+ Log.exception $!
20
73
  end
74
+ end
21
75
 
22
- Signal.trap(:INT){
23
- Kernel.exit! -1
24
- }
25
-
26
- loop do
27
- p = @queue.pop
28
- next if p.nil?
29
- raise p if Exception === p
30
- raise p.first if Exception === p.first
31
- res = @block.call *p
32
- @callback_queue.push res if @callback_queue
76
+ while true
77
+ pid, status = Process.waitpid2 @current
78
+ code = status.to_i >> 8
79
+ break unless code == 28
80
+ @current = Process.fork do
81
+ run
33
82
  end
34
- Kernel.exit! 0
35
- rescue ClosedStream
36
- rescue Aborted, Interrupt
37
- Log.warn "Worker #{Process.pid} aborted"
38
- Kernel.exit! 0
39
- rescue Exception
40
- Log.exception $!
41
- @callback_queue.push($!) if @callback_queue
42
- Kernel.exit! -1
43
- ensure
44
- @callback_queue.close_write if @callback_queue
83
+ Log.warn "Worker #{Process.pid} respawning to #{@current}"
84
+ end
85
+ rescue Aborted, Interrupt
86
+ Log.warn "Worker #{Process.pid} aborted"
87
+ Kernel.exit! 0
88
+ Process.kill "INT", @current
89
+ rescue Exception
90
+ Log.exception $!
91
+ raise $!
92
+ ensure
93
+ @monitor_thread.kill
94
+ Process.kill "INT", @current if Misc.pid_exists? @current
95
+ @callback_queue.close_write if @callback_queue
96
+ end
97
+
98
+ if status
99
+ Kernel.exit! status.to_i >> 8
100
+ else
101
+ Kernel.exit! -1
102
+ end
103
+ end
104
+
105
+ def initialize(queue, callback_queue = nil, cleanup = nil, respawn = false, &block)
106
+ @queue, @callback_queue, @cleanup, @block = queue, callback_queue, cleanup, block
107
+
108
+ @pid = Process.fork do
109
+ Misc.pre_fork
110
+
111
+ @cleanup.call if @cleanup
112
+ @queue.close_write
113
+
114
+ if @callback_queue
115
+ Misc.purge_pipes(@callback_queue.swrite)
116
+ @callback_queue.close_read
117
+ else
118
+ Misc.purge_pipes
119
+ end
120
+
121
+ if respawn
122
+ run_with_respawn respawn
123
+ else
124
+ run
45
125
  end
46
126
  end
47
127
  end
@@ -298,4 +298,8 @@ module Misc
298
298
  nil
299
299
  end
300
300
  end
301
+
302
+ def self.memory_use(pid=nil)
303
+ `ps -o rss -p #{pid || $$}`.strip.split.last.to_i
304
+ end
301
305
  end
@@ -19,6 +19,7 @@ Indicate the index file (TokyoCabinet BDB with source~target keys) as the <filen
19
19
  -t--target* Target entities
20
20
  -tsv--tsv* Output tsv
21
21
  EOF
22
+
22
23
  rbbt_usage and exit 0 if options[:help]
23
24
  filename = ARGV.shift
24
25
  raise ParameterException, "No filename specified" if filename.nil?
@@ -69,9 +69,36 @@ class TestConcurrencyProcess < Test::Unit::TestCase
69
69
  sleep 2
70
70
  q.clean
71
71
 
72
+
72
73
  q.join
73
74
  end
74
75
  end
76
+
77
+
78
+ def test_process_respawn
79
+ q = RbbtProcessQueue.new 2, nil, nil, true
80
+
81
+ res = []
82
+
83
+ q.callback do |v|
84
+ res << v
85
+ end
86
+
87
+ q.init do |i|
88
+ $str ||="-"
89
+ $str = $str * (2 + rand(5).to_i)
90
+ sleep 0.1
91
+ "."
92
+ end
93
+
94
+ times = 50
95
+
96
+ times.times do |i|
97
+ q.process i
98
+ end
99
+
100
+ q.join
101
+ end
75
102
  end
76
103
 
77
104
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.14.18
4
+ version: 5.14.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-26 00:00:00.000000000 Z
11
+ date: 2014-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake