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 +4 -4
- data/etc/app.d/entities.rb +0 -1
- data/lib/rbbt/knowledge_base.rb +86 -24
- data/lib/rbbt/tsv/attach/util.rb +3 -3
- data/lib/rbbt/tsv/manipulate.rb +10 -0
- data/lib/rbbt/tsv/parallel/traverse.rb +2 -2
- data/lib/rbbt/util/concurrency/processes.rb +4 -3
- data/lib/rbbt/util/concurrency/processes/worker.rb +114 -34
- data/lib/rbbt/util/misc/development.rb +4 -0
- data/share/rbbt_commands/association/subset +1 -0
- data/test/rbbt/util/concurrency/test_processes.rb +27 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5bc1786fca01c18645eeb743092710a25ebef1e
|
4
|
+
data.tar.gz: 7b4698982619547c6d37a6b0357f1937d33a7baa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fdf6ad7098498a63382450710dec248108f2956f8919ee72f63ee27fb1c9863eaedd449662ea709fce610c3735d6dc2eac37a3c58ad8c9451935ee32b8076ca1
|
7
|
+
data.tar.gz: 7d59b991703716459c7fec294b7acdffe8a55f33cd5ba989fc634d2e01a9be973ae092863f1aaeb661a16c662935c9ec858ecee98124c8aa4aa6995be25be743
|
data/etc/app.d/entities.rb
CHANGED
data/lib/rbbt/knowledge_base.rb
CHANGED
@@ -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
|
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(
|
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
|
-
|
158
|
+
key = name.to_s + "_" + Misc.digest(Misc.fingerprint([name,options,format,namespace]))
|
159
|
+
@databases[key] ||=
|
122
160
|
begin
|
123
|
-
Persist.memory("Database:" <<[
|
124
|
-
|
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
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
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
|
-
|
187
|
+
key = name.to_s + "_" + Misc.digest(Misc.fingerprint([name,options]))
|
188
|
+
@indices[key] ||=
|
141
189
|
begin
|
142
|
-
Persist.memory("Index:" <<[
|
143
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
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
|
-
|
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
|
data/lib/rbbt/tsv/attach/util.rb
CHANGED
@@ -34,12 +34,12 @@ module TSV
|
|
34
34
|
|
35
35
|
new_values.flatten if type == :flat
|
36
36
|
|
37
|
-
self[key] = current
|
37
|
+
self[key] = current + new_values
|
38
38
|
else
|
39
39
|
if type == :double
|
40
|
-
self[key] = current
|
40
|
+
self[key] = current + [[]] * fields.length
|
41
41
|
else
|
42
|
-
self[key] = current
|
42
|
+
self[key] = current + [nil] * fields.length
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
data/lib/rbbt/tsv/manipulate.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
@@ -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.
|
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-
|
11
|
+
date: 2014-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|