bud 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +9 -0
- data/README +30 -0
- data/bin/budplot +134 -0
- data/bin/budvis +201 -0
- data/bin/rebl +4 -0
- data/docs/README.md +13 -0
- data/docs/bfs.md +379 -0
- data/docs/bfs.raw +251 -0
- data/docs/bfs_arch.png +0 -0
- data/docs/bloom-loop.png +0 -0
- data/docs/bust.md +83 -0
- data/docs/cheat.md +291 -0
- data/docs/deploy.md +96 -0
- data/docs/diffs +181 -0
- data/docs/getstarted.md +296 -0
- data/docs/intro.md +36 -0
- data/docs/modules.md +112 -0
- data/docs/operational.md +96 -0
- data/docs/rebl.md +99 -0
- data/docs/ruby_hooks.md +19 -0
- data/docs/visualizations.md +75 -0
- data/examples/README +1 -0
- data/examples/basics/hello.rb +12 -0
- data/examples/basics/out +1103 -0
- data/examples/basics/out.new +856 -0
- data/examples/basics/paths.rb +51 -0
- data/examples/bust/README.md +9 -0
- data/examples/bust/bustclient-example.rb +23 -0
- data/examples/bust/bustinspector.html +135 -0
- data/examples/bust/bustserver-example.rb +18 -0
- data/examples/chat/README.md +9 -0
- data/examples/chat/chat.rb +45 -0
- data/examples/chat/chat_protocol.rb +8 -0
- data/examples/chat/chat_server.rb +29 -0
- data/examples/deploy/tokenring-ec2.rb +26 -0
- data/examples/deploy/tokenring-local.rb +17 -0
- data/examples/deploy/tokenring.rb +39 -0
- data/lib/bud/aggs.rb +126 -0
- data/lib/bud/bud_meta.rb +185 -0
- data/lib/bud/bust/bust.rb +126 -0
- data/lib/bud/bust/client/idempotence.rb +10 -0
- data/lib/bud/bust/client/restclient.rb +49 -0
- data/lib/bud/collections.rb +937 -0
- data/lib/bud/depanalysis.rb +44 -0
- data/lib/bud/deploy/countatomicdelivery.rb +50 -0
- data/lib/bud/deploy/deployer.rb +67 -0
- data/lib/bud/deploy/ec2deploy.rb +200 -0
- data/lib/bud/deploy/localdeploy.rb +41 -0
- data/lib/bud/errors.rb +15 -0
- data/lib/bud/graphs.rb +405 -0
- data/lib/bud/joins.rb +300 -0
- data/lib/bud/rebl.rb +314 -0
- data/lib/bud/rewrite.rb +523 -0
- data/lib/bud/rtrace.rb +27 -0
- data/lib/bud/server.rb +43 -0
- data/lib/bud/state.rb +108 -0
- data/lib/bud/storage/tokyocabinet.rb +170 -0
- data/lib/bud/storage/zookeeper.rb +178 -0
- data/lib/bud/stratify.rb +83 -0
- data/lib/bud/viz.rb +65 -0
- data/lib/bud.rb +797 -0
- metadata +330 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'tokyocabinet'
|
2
|
+
|
3
|
+
module Bud
|
4
|
+
# Persistent table implementation based on TokyoCabinet.
|
5
|
+
class BudTcTable < BudCollection # :nodoc: all
|
6
|
+
def initialize(name, bud_instance, given_schema)
|
7
|
+
tc_dir = bud_instance.options[:tc_dir]
|
8
|
+
raise BudError, "TC support must be enabled via 'tc_dir'" unless tc_dir
|
9
|
+
unless File.exists?(tc_dir)
|
10
|
+
Dir.mkdir(tc_dir)
|
11
|
+
puts "Created directory: #{tc_dir}" unless bud_instance.options[:quiet]
|
12
|
+
end
|
13
|
+
|
14
|
+
dirname = "#{tc_dir}/bud_#{bud_instance.port}"
|
15
|
+
unless File.exists?(dirname)
|
16
|
+
Dir.mkdir(dirname)
|
17
|
+
puts "Created directory: #{dirname}" unless bud_instance.options[:quiet]
|
18
|
+
end
|
19
|
+
|
20
|
+
super(name, bud_instance, given_schema)
|
21
|
+
@to_delete = []
|
22
|
+
|
23
|
+
@hdb = TokyoCabinet::HDB.new
|
24
|
+
db_fname = "#{dirname}/#{name}.tch"
|
25
|
+
flags = TokyoCabinet::HDB::OWRITER | TokyoCabinet::HDB::OCREAT
|
26
|
+
if bud_instance.options[:tc_truncate] == true
|
27
|
+
flags |= TokyoCabinet::HDB::OTRUNC
|
28
|
+
end
|
29
|
+
if !@hdb.open(db_fname, flags)
|
30
|
+
raise BudError, "Failed to open TokyoCabinet DB '#{db_fname}': #{@hdb.errmsg}"
|
31
|
+
end
|
32
|
+
@hdb.tranbegin
|
33
|
+
end
|
34
|
+
|
35
|
+
def init_storage
|
36
|
+
# XXX: we can't easily use the @storage infrastructure provided by
|
37
|
+
# BudCollection; issue #33
|
38
|
+
@storage = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def [](key)
|
42
|
+
key_s = MessagePack.pack(key)
|
43
|
+
val_s = @hdb[key_s]
|
44
|
+
if val_s
|
45
|
+
return make_tuple(key, MessagePack.unpack(val_s))
|
46
|
+
else
|
47
|
+
return @delta[key]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def has_key?(k)
|
52
|
+
key_s = MessagePack.pack(k)
|
53
|
+
return true if @hdb.has_key? key_s
|
54
|
+
return @delta.has_key? k
|
55
|
+
end
|
56
|
+
|
57
|
+
def include?(tuple)
|
58
|
+
key = @key_colnums.map{|k| tuple[k]}
|
59
|
+
value = self[key]
|
60
|
+
return (value == tuple)
|
61
|
+
end
|
62
|
+
|
63
|
+
def make_tuple(k_ary, v_ary)
|
64
|
+
t = Array.new(k_ary.length + v_ary.length)
|
65
|
+
@key_colnums.each_with_index do |k,i|
|
66
|
+
t[k] = k_ary[i]
|
67
|
+
end
|
68
|
+
val_cols.each_with_index do |c,i|
|
69
|
+
t[schema.index(c)] = v_ary[i]
|
70
|
+
end
|
71
|
+
tuple_accessors(t)
|
72
|
+
end
|
73
|
+
|
74
|
+
def each(&block)
|
75
|
+
each_from([@delta], &block)
|
76
|
+
each_storage(&block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def each_from(bufs, &block)
|
80
|
+
bufs.each do |b|
|
81
|
+
if b == @storage then
|
82
|
+
each_storage(&block)
|
83
|
+
else
|
84
|
+
b.each_value do |v|
|
85
|
+
yield v
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_storage(&block)
|
92
|
+
@hdb.each do |k,v|
|
93
|
+
k_ary = MessagePack.unpack(k)
|
94
|
+
v_ary = MessagePack.unpack(v)
|
95
|
+
yield make_tuple(k_ary, v_ary)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def flush
|
100
|
+
@hdb.trancommit
|
101
|
+
end
|
102
|
+
|
103
|
+
def close
|
104
|
+
@hdb.close
|
105
|
+
end
|
106
|
+
|
107
|
+
def merge_to_hdb(buf)
|
108
|
+
buf.each do |key,tuple|
|
109
|
+
merge_tuple(key, tuple)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def merge_tuple(key, tuple)
|
114
|
+
val = val_cols.map{|c| tuple[schema.index(c)]}
|
115
|
+
key_s = MessagePack.pack(key)
|
116
|
+
val_s = MessagePack.pack(val)
|
117
|
+
if @hdb.putkeep(key_s, val_s) == false
|
118
|
+
old_tuple = self[key]
|
119
|
+
raise_pk_error(tuple, old_tuple) if tuple != old_tuple
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# move deltas to TC, and new_deltas to deltas
|
124
|
+
def tick_deltas
|
125
|
+
merge_to_hdb(@delta)
|
126
|
+
@delta = @new_delta
|
127
|
+
@new_delta = {}
|
128
|
+
end
|
129
|
+
|
130
|
+
superator "<-" do |o|
|
131
|
+
o.each do |tuple|
|
132
|
+
@to_delete << tuple unless tuple.nil?
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def insert(tuple)
|
137
|
+
key = @key_colnums.map{|k| tuple[k]}
|
138
|
+
merge_tuple(key, tuple)
|
139
|
+
end
|
140
|
+
|
141
|
+
alias << insert
|
142
|
+
|
143
|
+
# Remove to_delete and then add pending to HDB
|
144
|
+
def tick
|
145
|
+
@to_delete.each do |tuple|
|
146
|
+
k = @key_colnums.map{|c| tuple[c]}
|
147
|
+
k_str = MessagePack.pack(k)
|
148
|
+
cols_str = @hdb[k_str]
|
149
|
+
unless cols_str.nil?
|
150
|
+
hdb_cols = MessagePack.unpack(cols_str)
|
151
|
+
delete_cols = val_cols.map{|c| tuple[schema.index(c)]}
|
152
|
+
if hdb_cols == delete_cols
|
153
|
+
@hdb.delete k_str
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
@to_delete = []
|
158
|
+
|
159
|
+
merge_to_hdb(@pending)
|
160
|
+
@pending = {}
|
161
|
+
|
162
|
+
@hdb.trancommit
|
163
|
+
@hdb.tranbegin
|
164
|
+
end
|
165
|
+
|
166
|
+
def method_missing(sym, *args, &block)
|
167
|
+
@hdb.send sym, *args, &block
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
begin
|
2
|
+
require 'zookeeper'
|
3
|
+
Bud::HAVE_ZOOKEEPER = true
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Bud
|
8
|
+
# Persistent table implementation based on Zookeeper.
|
9
|
+
class BudZkTable < BudCollection # :nodoc: all
|
10
|
+
def initialize(name, zk_path, zk_addr, bud_instance)
|
11
|
+
unless defined? HAVE_ZOOKEEPER
|
12
|
+
raise BudError, "zookeeper gem is not installed: zktables cannot be used"
|
13
|
+
end
|
14
|
+
|
15
|
+
# schema = {[:key] => [:val]}
|
16
|
+
super(name, bud_instance, nil)
|
17
|
+
|
18
|
+
zk_path = zk_path.chomp("/") unless zk_path == "/"
|
19
|
+
@zk = Zookeeper.new(zk_addr)
|
20
|
+
@zk_path = zk_path
|
21
|
+
@base_path = @zk_path
|
22
|
+
@base_path += "/" unless @zk_path.end_with? "/"
|
23
|
+
@store_mutex = Mutex.new
|
24
|
+
@next_storage = {}
|
25
|
+
@saw_delta = false
|
26
|
+
@child_watch_id = nil
|
27
|
+
@stat_watch_id = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# Since the watcher callbacks might invoke EventMachine, we wait until after
|
31
|
+
# EM startup to start watching for Zk events.
|
32
|
+
def start_watchers
|
33
|
+
# NB: Watcher callbacks are invoked in a separate Ruby thread.
|
34
|
+
@child_watcher = Zookeeper::WatcherCallback.new { get_and_watch }
|
35
|
+
@stat_watcher = Zookeeper::WatcherCallback.new { stat_and_watch }
|
36
|
+
stat_and_watch
|
37
|
+
end
|
38
|
+
|
39
|
+
def clone_empty
|
40
|
+
raise BudError
|
41
|
+
end
|
42
|
+
|
43
|
+
def stat_and_watch
|
44
|
+
r = @zk.stat(:path => @zk_path, :watcher => @stat_watcher)
|
45
|
+
@stat_watch_id = r[:req_id]
|
46
|
+
|
47
|
+
unless r[:stat].exists
|
48
|
+
cancel_child_watch
|
49
|
+
# The given @zk_path doesn't exist, so try to create it. Unclear
|
50
|
+
# whether this is always the best behavior.
|
51
|
+
r = @zk.create(:path => @zk_path)
|
52
|
+
if r[:rc] != Zookeeper::ZOK and r[:rc] != Zookeeper::ZNODEEXISTS
|
53
|
+
raise
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Make sure we're watching for children
|
58
|
+
get_and_watch unless @child_watch_id
|
59
|
+
end
|
60
|
+
|
61
|
+
def cancel_child_watch
|
62
|
+
if @child_watch_id
|
63
|
+
@zk.unregister_watcher(@child_watch_id)
|
64
|
+
@child_watch_id = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def cancel_stat_watch
|
69
|
+
if @stat_watch_id
|
70
|
+
@zk.unregister_watcher(@stat_watch_id)
|
71
|
+
@stat_with_id = nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_and_watch
|
76
|
+
r = @zk.get_children(:path => @zk_path, :watcher => @child_watcher)
|
77
|
+
@child_watch_id = r[:req_id]
|
78
|
+
unless r[:stat].exists
|
79
|
+
cancel_child_watch
|
80
|
+
return
|
81
|
+
end
|
82
|
+
|
83
|
+
# XXX: can we easily get snapshot isolation?
|
84
|
+
new_children = {}
|
85
|
+
r[:children].each do |c|
|
86
|
+
child_path = @base_path + c
|
87
|
+
|
88
|
+
get_r = @zk.get(:path => child_path)
|
89
|
+
unless get_r[:stat].exists
|
90
|
+
puts "ZK: failed to fetch child: #{child_path}"
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
data = get_r[:data]
|
95
|
+
# XXX: For now, conflate empty string values with nil values
|
96
|
+
data ||= ""
|
97
|
+
new_children[c] = tuple_accessors([c, data])
|
98
|
+
end
|
99
|
+
|
100
|
+
# We successfully fetched all the children of @zk_path; arrange to install
|
101
|
+
# the new data into @storage at the next Bud tick
|
102
|
+
need_tick = false
|
103
|
+
@store_mutex.synchronize {
|
104
|
+
@next_storage = new_children
|
105
|
+
if @storage != @next_storage
|
106
|
+
need_tick = true
|
107
|
+
@saw_delta = true
|
108
|
+
end
|
109
|
+
}
|
110
|
+
|
111
|
+
# If we have new data, force a new Bud tick in the near future
|
112
|
+
if need_tick and not @bud_instance.lazy
|
113
|
+
EventMachine::schedule {
|
114
|
+
@bud_instance.tick
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def tick
|
120
|
+
@store_mutex.synchronize {
|
121
|
+
return unless @saw_delta
|
122
|
+
@storage = @next_storage
|
123
|
+
@next_storage = {}
|
124
|
+
@saw_delta = false
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
def flush
|
129
|
+
each_from([@pending]) do |t|
|
130
|
+
path = @base_path + t.key
|
131
|
+
data = t.val
|
132
|
+
ephemeral = false
|
133
|
+
sequence = false
|
134
|
+
|
135
|
+
if t.length > 2
|
136
|
+
opts = t.last.first
|
137
|
+
if opts[:ephemeral] == true
|
138
|
+
ephemeral = true
|
139
|
+
end
|
140
|
+
if opts[:sequence] == true
|
141
|
+
sequence = true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
r = @zk.create(:path => path, :data => data,
|
146
|
+
:ephemeral => ephemeral, :sequence => sequence)
|
147
|
+
if r[:rc] == Zookeeper::ZNODEEXISTS
|
148
|
+
puts "Ignoring duplicate insert: #{t.inspect}"
|
149
|
+
elsif r[:rc] != Zookeeper::ZOK
|
150
|
+
puts "Failed create of #{path}: #{r.inspect}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
@pending.clear
|
154
|
+
end
|
155
|
+
|
156
|
+
def close
|
157
|
+
cancel_child_watch
|
158
|
+
cancel_stat_watch
|
159
|
+
@zk.close
|
160
|
+
end
|
161
|
+
|
162
|
+
superator "<~" do |o|
|
163
|
+
pending_merge(o)
|
164
|
+
end
|
165
|
+
|
166
|
+
superator "<+" do |o|
|
167
|
+
raise BudError, "Illegal use of <+ with zktable '#{@tabname}' on left"
|
168
|
+
end
|
169
|
+
|
170
|
+
def <=(o)
|
171
|
+
raise BudError, "Illegal use of <= with zktable '#{@tabname}' on left"
|
172
|
+
end
|
173
|
+
|
174
|
+
def <<(o)
|
175
|
+
raise BudError, "Illegal use of << with zktable '#{@tabname}' on left"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/bud/stratify.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bud'
|
3
|
+
|
4
|
+
class Stratification # :nodoc: all
|
5
|
+
include Bud
|
6
|
+
|
7
|
+
state do
|
8
|
+
# Data inserted by client (Bud rewrite code)
|
9
|
+
table :depends, [:rule, :head, :op, :body, :neg]
|
10
|
+
|
11
|
+
scratch :depends_clean, [:head, :body, :neg, :temporal]
|
12
|
+
scratch :depends_tc, [:head, :body, :via, :neg, :temporal]
|
13
|
+
scratch :cycle, [:predicate, :via, :neg, :temporal]
|
14
|
+
table :stratum_base, [:predicate, :stratum]
|
15
|
+
table :stratum, [:predicate, :stratum]
|
16
|
+
table :top_strat, [:stratum]
|
17
|
+
end
|
18
|
+
|
19
|
+
def declaration
|
20
|
+
strata[0] = lambda {
|
21
|
+
depends_clean <= depends do |d|
|
22
|
+
is_temporal = (d.op.to_s =~ /<[\+\-\~]/)
|
23
|
+
[d.head, d.body, d.neg, is_temporal]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Compute the transitive closure of "depends_clean" to detect cycles in
|
27
|
+
# the deductive fragment of the program.
|
28
|
+
depends_tc <= depends_clean do |d|
|
29
|
+
[d.head, d.body, d.body, d.neg, d.temporal]
|
30
|
+
end
|
31
|
+
depends_tc <= (depends_clean * depends_tc).pairs(:body => :head) do |b, r|
|
32
|
+
[b.head, r.body, b.body, (b.neg or r.neg), (b.temporal or r.temporal)]
|
33
|
+
end
|
34
|
+
|
35
|
+
cycle <= depends_tc do |d|
|
36
|
+
if d.head == d.body
|
37
|
+
if d.neg and !d.temporal
|
38
|
+
raise Bud::CompileError, "unstratifiable program: #{d.inspect}"
|
39
|
+
else
|
40
|
+
[d.head, d.via, d.neg, d.temporal]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# we initially assign all predicates to stratum 0
|
46
|
+
stratum_base <= depends {|d| [d.body, 0]}
|
47
|
+
}
|
48
|
+
|
49
|
+
strata[1] = lambda {
|
50
|
+
# classic stratification:
|
51
|
+
# if A depends on B, A is >= B.
|
52
|
+
# if A depends nonmonotonically on B, A > B.
|
53
|
+
# if A are B are co-dependent, give up.
|
54
|
+
# (don't need to do this, b/c we've ruled out deductive cycles)
|
55
|
+
# stratum choice will represent local evaluation order,
|
56
|
+
# so we need only consider 'synchronous' dependencies (<=)
|
57
|
+
|
58
|
+
# pass 1: assume no deductive cycles
|
59
|
+
# do "vanilla stratification" on deductive rules
|
60
|
+
stratum_base <= (depends * stratum_base).pairs(:body => :predicate) do |d, s|
|
61
|
+
if d.op.to_s == '<='
|
62
|
+
if d.neg
|
63
|
+
# BUMP
|
64
|
+
[d.head, s.stratum + 1]
|
65
|
+
else
|
66
|
+
# HOIST
|
67
|
+
[d.head, s.stratum]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
strata[2] = lambda {
|
74
|
+
stratum <= stratum_base.group([stratum_base.predicate], max(stratum_base.stratum))
|
75
|
+
}
|
76
|
+
|
77
|
+
strata[3] = lambda {
|
78
|
+
# there is no good reason that top_strat can't be computed in strata[3] over stratum_base.
|
79
|
+
# however, when it is deduced that way, it is empty after a tick
|
80
|
+
top_strat <= stratum.group([], max(stratum.stratum))
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
data/lib/bud/viz.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'syntax/convertors/html'
|
3
|
+
require 'gchart'
|
4
|
+
require 'digest/md5'
|
5
|
+
require 'bud/state'
|
6
|
+
|
7
|
+
class VizOnline #:nodoc: all
|
8
|
+
def initialize(bud_instance)
|
9
|
+
@bud_instance = bud_instance
|
10
|
+
return if bud_instance.class == Stratification or @bud_instance.class == DepAnalysis
|
11
|
+
@meta_tables = {'t_rules' => 1, 't_depends' => 1, 't_table_info' => 1, 't_cycle' => 1, 't_stratum' => 1, 't_depends_tc' => 1, 't_table_schema' => 1}
|
12
|
+
@bud_instance.options[:tc_dir] = "TC_#{@bud_instance.class}_#{bud_instance.options[:tag]}_#{bud_instance.object_id}_#{bud_instance.port}"
|
13
|
+
@table_info = new_tab(:t_table_info, [:tab_name, :tab_type], @bud_instance)
|
14
|
+
@table_schema = new_tab(:t_table_schema, [:tab_name, :col_name, :ord], @bud_instance)
|
15
|
+
|
16
|
+
@logtab = {}
|
17
|
+
tmp_set = []
|
18
|
+
@bud_instance.tables.each do |name, tbl|
|
19
|
+
next if name.to_s =~ /_vizlog\z/
|
20
|
+
|
21
|
+
# Temp collections don't have a schema until a fact has been inserted into
|
22
|
+
# them; for now, we just include an empty schema for them in the viz
|
23
|
+
if tbl.schema.nil?
|
24
|
+
schema = []
|
25
|
+
else
|
26
|
+
schema = tbl.schema.clone
|
27
|
+
end
|
28
|
+
tmp_set << [name, schema, tbl.class.to_s]
|
29
|
+
end
|
30
|
+
|
31
|
+
tmp_set.each do |t|
|
32
|
+
news = [:c_bud_time]
|
33
|
+
@table_schema << [t[0], :c_bud_time, 0]
|
34
|
+
t[1].each_with_index do |s, i|
|
35
|
+
news << s
|
36
|
+
@table_schema << [t[0], s, i+1]
|
37
|
+
end
|
38
|
+
lt = "#{t[0]}_vizlog".to_sym
|
39
|
+
@logtab[t[0]] = new_tab(lt, news, @bud_instance)
|
40
|
+
@table_info << [t[0], t[2]]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def new_tab(name, schema, instance)
|
45
|
+
ret = Bud::BudTcTable.new(name, instance, schema)
|
46
|
+
instance.tables[name] = ret
|
47
|
+
return ret
|
48
|
+
end
|
49
|
+
|
50
|
+
def do_cards
|
51
|
+
return if @bud_instance.class == Stratification or @bud_instance.class == DepAnalysis
|
52
|
+
@bud_instance.tables.each do |t|
|
53
|
+
tab = t[0]
|
54
|
+
next if tab.to_s =~ /_vizlog\z/
|
55
|
+
next if @meta_tables[tab.to_s] and @bud_instance.budtime > 0
|
56
|
+
next unless @logtab[tab]
|
57
|
+
t[1].each do |row|
|
58
|
+
newrow = [@bud_instance.budtime]
|
59
|
+
row.each{ |r| newrow << r }
|
60
|
+
@logtab[tab] << newrow
|
61
|
+
end
|
62
|
+
@logtab[tab].tick
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|