rbbt-util 5.13.31 → 5.13.32
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/bin/rbbt +11 -0
- data/lib/rbbt/monitor.rb +152 -10
- data/lib/rbbt/persist/tsv/adapter.rb +109 -0
- data/lib/rbbt/persist/tsv/kyotocabinet.rb +3 -77
- data/lib/rbbt/persist/tsv/lmdb.rb +1 -88
- data/lib/rbbt/persist/tsv/tokyocabinet.rb +126 -93
- data/lib/rbbt/persist/tsv.rb +2 -0
- data/lib/rbbt/persist.rb +21 -91
- data/lib/rbbt/tsv/parallel/traverse.rb +9 -5
- data/lib/rbbt/util/cmd.rb +1 -1
- data/lib/rbbt/util/log.rb +7 -6
- data/lib/rbbt/util/misc/concurrent_stream.rb +2 -1
- data/lib/rbbt/util/misc/development.rb +23 -0
- data/lib/rbbt/util/misc/lock.rb +18 -13
- data/lib/rbbt/util/misc/pipes.rb +23 -11
- data/lib/rbbt/util/open.rb +5 -5
- data/lib/rbbt/util/simpleopt/doc.rb +1 -1
- data/lib/rbbt/workflow/step/run.rb +3 -2
- data/lib/rbbt/workflow/step.rb +7 -1
- data/lib/rbbt/workflow.rb +18 -11
- data/share/rbbt_commands/system/clean +57 -58
- data/share/rbbt_commands/system/status +59 -40
- data/share/rbbt_commands/tsv/info +1 -1
- data/test/rbbt/test_monitor.rb +13 -0
- data/test/rbbt/tsv/parallel/test_traverse.rb +44 -22
- data/test/rbbt/util/test_misc.rb +10 -0
- data/test/rbbt/util/test_open.rb +16 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03d6c0cd25cb674bc5fb28731e6c936d32a8468c
|
4
|
+
data.tar.gz: 0a8c5ba0281f806e9d8712e527b011bae576bacf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24555145911d44367c1b9ddfe30c96b7e205811b9838508e68faebeb07da384b4fdc1d9bed59a221f97b00e51ba8ea816fccbb7c26517de79433e3306a9e8fbc
|
7
|
+
data.tar.gz: 6b275e80ce80ac94a8067c8f255c50d718fab0717934ff46e5354640951d4f94ae5361cb92d429b2cd14ba3edaea35f5dd26e9748eb4021a53bd1c33f576592b
|
data/bin/rbbt
CHANGED
@@ -42,8 +42,19 @@ $ rbbt <command> <subcommand> ... -a --arg1 --arg2='value' --arg3 'another-value
|
|
42
42
|
--nocolor #{Log.color :yellow, "Disable colored output"}
|
43
43
|
--nobar #{Log.color :yellow, "Disable progress report"}
|
44
44
|
--locate_file #{Log.color :yellow, "Report the location of the script instead of executing it"}
|
45
|
+
--dump_mem* #{Log.color :yellow, "Dump strings in memory each second into file"}
|
46
|
+
--no_lock_id #{Log.color :yellow, "Do not track lockfiles with ids (for high-througput and high-concurrency"}
|
45
47
|
EOF
|
46
48
|
|
49
|
+
if options.delete(:no_lock_id)
|
50
|
+
Misc.use_lock_id = false
|
51
|
+
end
|
52
|
+
|
53
|
+
if mem_dump = options.delete(:dump_mem)
|
54
|
+
require 'rbbt/monitor'
|
55
|
+
Rbbt.dump_memory(mem_dump, Symbol)
|
56
|
+
end
|
57
|
+
|
47
58
|
if options.delete :nobar
|
48
59
|
ENV["RBBT_NO_PROGRESS"] = "true"
|
49
60
|
end
|
data/lib/rbbt/monitor.rb
CHANGED
@@ -5,28 +5,170 @@ module Rbbt
|
|
5
5
|
LOCK_DIRS = Rbbt.share.find_all + Rbbt.var.cache.persistence.find_all + Rbbt.var.jobs.find_all +
|
6
6
|
Rbbt.tmp.tsv_open_locks.find_all + Rbbt.tmp.persist_locks.find_all
|
7
7
|
|
8
|
+
SENSIBLE_WRITE_DIRS = Misc.sensiblewrite_dir.find_all
|
9
|
+
|
10
|
+
PERSIST_DIRS = Rbbt.share.find_all + Rbbt.var.cache.persistence.find_all
|
11
|
+
|
12
|
+
JOB_DIRS = Rbbt.var.jobs.find_all
|
13
|
+
|
14
|
+
def self.dump_memory(file, obj = nil)
|
15
|
+
Log.info "Dumping #{obj} objects into #{ file }"
|
16
|
+
Thread.new do
|
17
|
+
while true
|
18
|
+
Open.write(file) do |f|
|
19
|
+
Thread.exclusive do
|
20
|
+
GC.start
|
21
|
+
ObjectSpace.each_object(obj) do |o|
|
22
|
+
f.puts "---"
|
23
|
+
f.puts(String === o ? o : o.inspect)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
FileUtils.cp file, file + '.save'
|
28
|
+
sleep 3
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.file_time(file)
|
34
|
+
ctime = File.ctime file
|
35
|
+
atime = File.atime file
|
36
|
+
elapsed = Time.now - ctime
|
37
|
+
{:ctime => ctime, :atime => atime, :elapsed => elapsed}
|
38
|
+
end
|
39
|
+
|
40
|
+
#{{{ LOCKS
|
41
|
+
|
8
42
|
def self.locks(dirs = LOCK_DIRS)
|
9
43
|
dirs.collect do |dir|
|
10
|
-
dir
|
11
|
-
|
44
|
+
next unless Open.exists? dir
|
45
|
+
`find "#{ dir }" -name "*.lock"`.split "\n"
|
46
|
+
end.compact.flatten
|
12
47
|
end
|
13
48
|
|
14
|
-
|
49
|
+
def self.lock_info(dirs = LOCK_DIRS)
|
50
|
+
lock_info = {}
|
51
|
+
locks(dirs).each do |f|
|
52
|
+
begin
|
53
|
+
i = file_time(f)
|
54
|
+
if File.size(f) > 0
|
55
|
+
info = Open.open(f) do |s|
|
56
|
+
YAML.load(s)
|
57
|
+
end
|
58
|
+
i[:pid] = info[:pid]
|
59
|
+
i[:ppid] = info[:ppid]
|
60
|
+
end
|
61
|
+
lock_info[f] = i
|
62
|
+
rescue
|
63
|
+
Log.exception $!
|
64
|
+
end
|
65
|
+
end
|
66
|
+
lock_info
|
67
|
+
end
|
68
|
+
|
69
|
+
#{{{ SENSIBLE WRITES
|
70
|
+
|
15
71
|
def self.sensiblewrites(dirs = SENSIBLE_WRITE_DIRS)
|
16
72
|
dirs.collect do |dir|
|
17
|
-
|
18
|
-
|
73
|
+
next unless Open.exists? dir
|
74
|
+
`find "#{ dir }" -not -name "*.lock" -not -type d`.split "\n"
|
75
|
+
end.compact.flatten
|
19
76
|
end
|
20
77
|
|
21
|
-
|
78
|
+
def self.sensiblewrite_info(dirs = SENSIBLE_WRITE_DIRS)
|
79
|
+
info = {}
|
80
|
+
sensiblewrites(dirs).each do |f|
|
81
|
+
begin
|
82
|
+
i = file_time(f)
|
83
|
+
info[f] = i
|
84
|
+
rescue
|
85
|
+
Log.exception $!
|
86
|
+
end
|
87
|
+
end
|
88
|
+
info
|
89
|
+
end
|
90
|
+
|
91
|
+
# PERSISTS
|
92
|
+
|
22
93
|
def self.persists(dirs = PERSIST_DIRS)
|
23
94
|
dirs.collect do |dir|
|
24
|
-
|
25
|
-
|
95
|
+
next unless Open.exists? dir
|
96
|
+
`find "#{ dir }" -name "*.persist"`.split "\n"
|
97
|
+
end.compact.flatten
|
26
98
|
end
|
27
99
|
|
28
|
-
|
29
|
-
|
100
|
+
def self.persist_info(dirs = PERSIST_DIRS)
|
101
|
+
info = {}
|
102
|
+
persists(dirs).each do |f|
|
103
|
+
begin
|
104
|
+
i = file_time(f)
|
105
|
+
info[f] = i
|
106
|
+
rescue
|
107
|
+
Log.exception $!
|
108
|
+
end
|
109
|
+
end
|
110
|
+
info
|
111
|
+
end
|
112
|
+
|
113
|
+
# PERSISTS
|
114
|
+
|
115
|
+
def self.job_info(workflows = nil, tasks = nil, dirs = JOB_DIRS)
|
116
|
+
require 'rbbt/workflow/step'
|
117
|
+
|
118
|
+
workflows = [workflows] if workflows and not Array === workflows
|
119
|
+
workflows = workflows.collect{|w| w.to_s} if workflows
|
120
|
+
|
121
|
+
tasks = [tasks] if tasks and not Array === tasks
|
122
|
+
tasks = tasks.collect{|w| w.to_s} if tasks
|
123
|
+
|
124
|
+
jobs = {}
|
125
|
+
dirs.collect do |dir|
|
126
|
+
next unless Open.exists? dir
|
127
|
+
|
128
|
+
dir.glob("*").collect do |workflowdir|
|
129
|
+
workflow = File.basename(workflowdir)
|
130
|
+
next if workflows and not workflows.include? workflow
|
131
|
+
|
132
|
+
workflowdir.glob("*").collect do |taskdir|
|
133
|
+
task = File.basename(taskdir)
|
134
|
+
next if tasks and not tasks.include? task
|
135
|
+
|
136
|
+
files = `find "#{ taskdir }/" -not -type d -not -path "*/*.files/*"`.split("\n").sort
|
137
|
+
_files = Set.new files
|
138
|
+
TSV.traverse files, :type => :array, :into => jobs do |file|
|
139
|
+
if m = file.match(/(.*).info$/)
|
140
|
+
file = m[1]
|
141
|
+
end
|
142
|
+
|
143
|
+
name = file[taskdir.length+1..-1]
|
144
|
+
info_file = file + '.info'
|
145
|
+
|
146
|
+
info = {}
|
147
|
+
|
148
|
+
info[:workflow] = workflow
|
149
|
+
info[:task] = task
|
150
|
+
info[:name] = name
|
151
|
+
|
152
|
+
if _files.include? file
|
153
|
+
info = info.merge(file_time(file))
|
154
|
+
info[:done] = true
|
155
|
+
info[:info_file] = File.exists?(info_file) ? info_file : nil
|
156
|
+
else
|
157
|
+
info = info.merge({:info_file => info_file, :done => false})
|
158
|
+
end
|
159
|
+
|
160
|
+
[file, info]
|
161
|
+
end
|
162
|
+
|
163
|
+
end.compact.flatten
|
164
|
+
end.compact.flatten
|
165
|
+
end.compact.flatten
|
166
|
+
jobs
|
167
|
+
end
|
168
|
+
|
169
|
+
# REST
|
170
|
+
|
171
|
+
def self.__jobs(dirs = JOB_DIRS)
|
30
172
|
job_files = {}
|
31
173
|
dirs.each do |dir|
|
32
174
|
workflow_dirs = dir.glob("*").each do |wdir|
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rbbt/tsv'
|
2
|
+
module Persist
|
3
|
+
module TSVAdapter
|
4
|
+
attr_accessor :persistence_path, :closed, :writable, :mutex
|
5
|
+
|
6
|
+
MAX_CHAR = 255.chr
|
7
|
+
|
8
|
+
def mutex
|
9
|
+
@mutex ||= Mutex.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def prefix(key)
|
13
|
+
range(key, 1, key + MAX_CHAR, 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_prefix(key)
|
17
|
+
keys = prefix(key)
|
18
|
+
select(:key => keys)
|
19
|
+
end
|
20
|
+
|
21
|
+
def closed?
|
22
|
+
@closed
|
23
|
+
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
@closed = true
|
27
|
+
super
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def write?
|
32
|
+
@writable
|
33
|
+
end
|
34
|
+
|
35
|
+
def read?
|
36
|
+
! write?
|
37
|
+
end
|
38
|
+
|
39
|
+
def collect
|
40
|
+
res = []
|
41
|
+
each do |key, value|
|
42
|
+
res << if block_given?
|
43
|
+
yield key, value
|
44
|
+
else
|
45
|
+
[key, value]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
res
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete(key)
|
52
|
+
out(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_and_read
|
56
|
+
lock_filename = Persist.persistence_path(persistence_path + '.write', {:dir => TSV.lock_dir})
|
57
|
+
Misc.lock(lock_filename) do
|
58
|
+
mutex.synchronize do
|
59
|
+
write if closed? or not write?
|
60
|
+
res = begin
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
read
|
64
|
+
end
|
65
|
+
res
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def write_and_close
|
71
|
+
lock_filename = Persist.persistence_path(persistence_path + '.write', {:dir => TSV.lock_dir})
|
72
|
+
Misc.lock(lock_filename) do
|
73
|
+
mutex.synchronize do
|
74
|
+
write if closed? or not write?
|
75
|
+
res = begin
|
76
|
+
yield
|
77
|
+
ensure
|
78
|
+
close
|
79
|
+
end
|
80
|
+
res
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def read_and_close
|
86
|
+
mutex.synchronize do
|
87
|
+
read if closed? or not read?
|
88
|
+
res = begin
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
close
|
92
|
+
end
|
93
|
+
res
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def merge!(hash)
|
99
|
+
hash.each do |key,values|
|
100
|
+
self[key] = values
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
def range(*args)
|
106
|
+
super(*args) #- TSV::ENTRY_KEYS.to_a
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -3,7 +3,8 @@ require 'kyotocabinet'
|
|
3
3
|
module Persist
|
4
4
|
|
5
5
|
module KCAdapter
|
6
|
-
|
6
|
+
include Persist::TSVAdapter
|
7
|
+
attr_accessor :kyotocabinet_class
|
7
8
|
|
8
9
|
def self.open(path, write, kyotocabinet_class = "kch")
|
9
10
|
real_path = path + ".#{kyotocabinet_class}"
|
@@ -24,33 +25,10 @@ module Persist
|
|
24
25
|
database
|
25
26
|
end
|
26
27
|
|
27
|
-
def keys
|
28
|
-
keys = []
|
29
|
-
each_key{|k| keys.concat k}
|
30
|
-
keys
|
31
|
-
end
|
32
|
-
|
33
|
-
def prefix(key)
|
34
|
-
range(key, 1, key + 255.chr, 1)
|
35
|
-
end
|
36
|
-
|
37
|
-
def get_prefix(key)
|
38
|
-
keys = prefix(key)
|
39
|
-
select(:key => keys)
|
40
|
-
end
|
41
|
-
|
42
|
-
def include?(key)
|
43
|
-
value = get(key)
|
44
|
-
! value.nil?
|
45
|
-
end
|
46
|
-
|
47
|
-
def closed?
|
48
|
-
@closed
|
49
|
-
end
|
50
|
-
|
51
28
|
def close
|
52
29
|
@closed = true
|
53
30
|
super
|
31
|
+
self
|
54
32
|
end
|
55
33
|
|
56
34
|
def read(force = false)
|
@@ -96,58 +74,6 @@ module Persist
|
|
96
74
|
def delete(key)
|
97
75
|
out(key)
|
98
76
|
end
|
99
|
-
|
100
|
-
def write_and_read
|
101
|
-
lock_filename = Persist.persistence_path(persistence_path, {:dir => TSV.lock_dir})
|
102
|
-
Misc.lock(lock_filename) do
|
103
|
-
write if @closed or not write?
|
104
|
-
res = begin
|
105
|
-
yield
|
106
|
-
ensure
|
107
|
-
read
|
108
|
-
end
|
109
|
-
res
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def write_and_close
|
114
|
-
lock_filename = Persist.persistence_path(persistence_path, {:dir => TSV.lock_dir})
|
115
|
-
Misc.lock(lock_filename) do
|
116
|
-
write if @closed or not write?
|
117
|
-
res = begin
|
118
|
-
yield
|
119
|
-
ensure
|
120
|
-
close
|
121
|
-
end
|
122
|
-
res
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def read_and_close
|
127
|
-
read if @closed or write?
|
128
|
-
res = begin
|
129
|
-
yield
|
130
|
-
ensure
|
131
|
-
close
|
132
|
-
end
|
133
|
-
res
|
134
|
-
end
|
135
|
-
|
136
|
-
def merge!(hash)
|
137
|
-
hash.each do |key,values|
|
138
|
-
self[key] = values
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
#def []=(key,value)
|
143
|
-
# super(key,value)
|
144
|
-
# self.synchronize
|
145
|
-
#end
|
146
|
-
|
147
|
-
|
148
|
-
def range(*args)
|
149
|
-
super(*args) - TSV::ENTRY_KEYS.to_a
|
150
|
-
end
|
151
77
|
end
|
152
78
|
|
153
79
|
|
@@ -3,8 +3,7 @@ require 'lmdb'
|
|
3
3
|
module Persist
|
4
4
|
|
5
5
|
module LMDBAdapter
|
6
|
-
|
7
|
-
|
6
|
+
include Persist::TSVAdapter
|
8
7
|
def self.open(path, write)
|
9
8
|
|
10
9
|
database = CONNECTIONS[path] ||= begin
|
@@ -21,40 +20,6 @@ module Persist
|
|
21
20
|
database
|
22
21
|
end
|
23
22
|
|
24
|
-
def keys
|
25
|
-
keys = []
|
26
|
-
cursor do |cursor|
|
27
|
-
while p = cursor.next
|
28
|
-
keys << p.first
|
29
|
-
end
|
30
|
-
end
|
31
|
-
keys
|
32
|
-
end
|
33
|
-
|
34
|
-
def include?(key)
|
35
|
-
self.send(:[], key, true)
|
36
|
-
end
|
37
|
-
|
38
|
-
def closed?
|
39
|
-
false
|
40
|
-
end
|
41
|
-
|
42
|
-
def close
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
def read(force = false)
|
47
|
-
self
|
48
|
-
end
|
49
|
-
|
50
|
-
def write(force = true)
|
51
|
-
self
|
52
|
-
end
|
53
|
-
|
54
|
-
def write?
|
55
|
-
@writable
|
56
|
-
end
|
57
|
-
|
58
23
|
def each
|
59
24
|
cursor do |cursor|
|
60
25
|
while pair = cursor.next
|
@@ -77,60 +42,8 @@ module Persist
|
|
77
42
|
end
|
78
43
|
res
|
79
44
|
end
|
80
|
-
|
81
|
-
def delete(key)
|
82
|
-
out(key)
|
83
|
-
end
|
84
|
-
|
85
|
-
def write_and_read
|
86
|
-
lock_filename = Persist.persistence_path(persistence_path, {:dir => TSV.lock_dir})
|
87
|
-
Misc.lock(lock_filename) do
|
88
|
-
write if @closed or not write?
|
89
|
-
res = begin
|
90
|
-
yield
|
91
|
-
ensure
|
92
|
-
read
|
93
|
-
end
|
94
|
-
res
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def write_and_close
|
99
|
-
lock_filename = Persist.persistence_path(persistence_path, {:dir => TSV.lock_dir})
|
100
|
-
Misc.lock(lock_filename) do
|
101
|
-
write if @closed or not write?
|
102
|
-
res = begin
|
103
|
-
yield
|
104
|
-
ensure
|
105
|
-
close
|
106
|
-
end
|
107
|
-
res
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def read_and_close
|
112
|
-
read if @closed or write?
|
113
|
-
res = begin
|
114
|
-
yield
|
115
|
-
ensure
|
116
|
-
close
|
117
|
-
end
|
118
|
-
res
|
119
|
-
end
|
120
|
-
|
121
|
-
def merge!(hash)
|
122
|
-
hash.each do |key,values|
|
123
|
-
self[key] = values
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
|
128
|
-
def range(*args)
|
129
|
-
super(*args) - TSV::ENTRY_KEYS.to_a
|
130
|
-
end
|
131
45
|
end
|
132
46
|
|
133
|
-
|
134
47
|
def self.open_lmdb(path, write, serializer = nil)
|
135
48
|
write = true unless File.exists? path
|
136
49
|
|