bud 0.0.8 → 0.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +4 -10
- data/bin/budplot +1 -2
- data/docs/cheat.md +2 -15
- data/examples/basics/paths.rb +7 -7
- data/lib/bud/aggs.rb +15 -19
- data/lib/bud/bud_meta.rb +165 -77
- data/lib/bud/bust/bust.rb +11 -4
- data/lib/bud/collections.rb +643 -280
- data/lib/bud/depanalysis.rb +50 -25
- data/lib/bud/executor/elements.rb +592 -0
- data/lib/bud/executor/group.rb +104 -0
- data/lib/bud/executor/join.rb +638 -0
- data/lib/bud/graphs.rb +12 -11
- data/lib/bud/joins.rb +2 -1
- data/lib/bud/meta_algebra.rb +5 -4
- data/lib/bud/metrics.rb +9 -3
- data/lib/bud/monkeypatch.rb +131 -23
- data/lib/bud/rebl.rb +41 -28
- data/lib/bud/rewrite.rb +112 -440
- data/lib/bud/server.rb +3 -2
- data/lib/bud/source.rb +109 -0
- data/lib/bud/state.rb +16 -9
- data/lib/bud/storage/dbm.rb +62 -16
- data/lib/bud/storage/zookeeper.rb +2 -2
- data/lib/bud/viz.rb +8 -4
- data/lib/bud/viz_util.rb +10 -9
- data/lib/bud.rb +413 -199
- metadata +40 -55
- data/examples/deploy/tokenring-ec2.rb +0 -26
- data/examples/deploy/tokenring-fork.rb +0 -15
- data/examples/deploy/tokenring-thread.rb +0 -15
- data/examples/deploy/tokenring.rb +0 -47
- data/lib/bud/deploy/deployer.rb +0 -67
- data/lib/bud/deploy/ec2deploy.rb +0 -199
- data/lib/bud/deploy/forkdeploy.rb +0 -90
- data/lib/bud/deploy/threaddeploy.rb +0 -38
- data/lib/bud/storage/tokyocabinet.rb +0 -190
- data/lib/bud/stratify.rb +0 -85
data/README
CHANGED
@@ -10,15 +10,11 @@ documentation.
|
|
10
10
|
|
11
11
|
Main deficiencies at this point are:
|
12
12
|
|
13
|
-
- Inefficient evaluation: Programs are run using semi-naive evaluation
|
14
|
-
strategies, but no further query optimization has been implemented, and little
|
15
|
-
effort has been spent in tuning.
|
16
|
-
|
17
13
|
- No Ruby constraints: Within Bloom programs the full power of Ruby is also
|
18
14
|
available, including mutable state. This allows programmers to get outside
|
19
15
|
the Bloom framework and lose cleanliness.
|
20
16
|
|
21
|
-
- Compatibility: Bud only works with Ruby (MRI) 1.8
|
17
|
+
- Compatibility: Bud only works with Ruby (MRI) 1.8 and 1.9. JRuby and other
|
22
18
|
Ruby implementations are currently not supported.
|
23
19
|
|
24
20
|
## Installation
|
@@ -39,8 +35,6 @@ To run the unit tests:
|
|
39
35
|
|
40
36
|
## Optional Dependencies
|
41
37
|
|
42
|
-
The bud gem has a handful of mandatory dependencies. It also has
|
43
|
-
|
44
|
-
|
45
|
-
before installing the "tokyocabinet" gem, the Tokyo Cabinet libraries should be
|
46
|
-
installed first.
|
38
|
+
The bud gem has a handful of mandatory dependencies. It also has one optional
|
39
|
+
dependency: if you wish to use Bud collections backed by Zookeeper, the
|
40
|
+
"zookeeper" gem must be installed.
|
data/bin/budplot
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'bud'
|
4
4
|
require 'bud/bud_meta'
|
5
|
-
require 'bud/depanalysis'
|
6
5
|
require 'bud/graphs'
|
7
6
|
require 'bud/meta_algebra'
|
8
7
|
require 'bud/viz_util'
|
@@ -33,7 +32,7 @@ def make_instance(mods)
|
|
33
32
|
if mods.length == 1
|
34
33
|
return mod_klass.new
|
35
34
|
else
|
36
|
-
puts "Error: cannot intermix
|
35
|
+
puts "Error: cannot intermix class \"#{mod_klass}\" with modules"
|
37
36
|
exit
|
38
37
|
end
|
39
38
|
elsif mod_klass.class != Module
|
data/docs/cheat.md
CHANGED
@@ -114,13 +114,12 @@ Built-in scratch collection to be used on the lhs of a rule; permanently halts t
|
|
114
114
|
If the item `[:kill]` is inserted, the Bud OS process (including all Bud instances) is also halted.
|
115
115
|
|
116
116
|
### sync ###
|
117
|
-
Persistent collection mapped to an external storage engine, with synchronous write-flushing each timestep.
|
117
|
+
Persistent collection mapped to an external storage engine, with synchronous write-flushing each timestep.
|
118
118
|
Default attributes: `[:key] => [:val]`.
|
119
119
|
|
120
120
|
sync :s1, :dbm
|
121
|
-
sync :s2, :tokyo, [:k1, :k2] => [:v1, :v2]
|
122
121
|
|
123
|
-
|
122
|
+
Currently only [dbm](http://en.wikipedia.org/wiki/Dbm) is supported. Support for tokyo cabinet present in an earlier release has been removed.<br>
|
124
123
|
|
125
124
|
### store ###
|
126
125
|
Persistent collection mapped to an external storage engine, with asynchronous write-flushing. Supported storage engines: `:zookeeper`.<br>
|
@@ -173,8 +172,6 @@ implicit map:
|
|
173
172
|
|
174
173
|
`flat_map`:
|
175
174
|
|
176
|
-
require 'backports' # flat_map not included in Ruby 1.8 by default
|
177
|
-
|
178
175
|
t3 <= bc.flat_map do |t| # unnest a collection-valued attribute
|
179
176
|
bc.col4.map { |sub| [t.col1, t.col2, t.col3, sub] }
|
180
177
|
end
|
@@ -323,16 +320,6 @@ The schema of a temp collection in inherited from the rhs; if the rhs has no
|
|
323
320
|
schema, a simple one is manufactured to suit the data found in the rhs at
|
324
321
|
runtime: `[c0, c1, ...]`.
|
325
322
|
|
326
|
-
`with`<br>
|
327
|
-
With statements define a temp collection that can be referenced only within the scope of the associated block. They are useful when you "fork" in a dataflow into two lhs destinations:
|
328
|
-
|
329
|
-
with :biggies <= request {|r| r if r.quantity > 100}, begin
|
330
|
-
to_process <= (biggies * known_good).lefts(:key=>:key)
|
331
|
-
denied <= (biggies * known_good).nopairs(:key=>key)
|
332
|
-
end
|
333
|
-
|
334
|
-
The advantage of using `with` over `temp` is modularity: all the rules referencing `biggies` have to be bundled together, making it easier to see that the contents of `request` with quantity > 100 are handled properly.
|
335
|
-
|
336
323
|
## Bud Modules ##
|
337
324
|
A Bud module combines state (collections) and logic (Bloom rules). Using modules allows your program to be decomposed into a collection of smaller units.
|
338
325
|
|
data/examples/basics/paths.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# simple shortest paths
|
2
|
-
# note use of program.tick at bottom to run a single
|
2
|
+
# note use of program.tick at bottom to run a single timestep
|
3
3
|
# and inspect relations
|
4
4
|
require 'rubygems'
|
5
5
|
require 'bud'
|
@@ -9,19 +9,19 @@ class ShortestPaths
|
|
9
9
|
|
10
10
|
state do
|
11
11
|
table :link, [:from, :to, :cost]
|
12
|
-
table :path, [:from, :to, :
|
13
|
-
table :shortest, [:from, :to] => [:
|
12
|
+
table :path, [:from, :to, :nxt, :cost]
|
13
|
+
table :shortest, [:from, :to] => [:nxt, :cost]
|
14
14
|
end
|
15
15
|
|
16
16
|
# recursive rules to define all paths from links
|
17
17
|
bloom :make_paths do
|
18
18
|
# base case: every link is a path
|
19
|
-
path <= link {|
|
19
|
+
path <= link {|l| [l.from, l.to, l.to, l.cost]}
|
20
20
|
|
21
21
|
# inductive case: make path of length n+1 by connecting a link to a path of
|
22
22
|
# length n
|
23
23
|
path <= (link*path).pairs(:to => :from) do |l,p|
|
24
|
-
[l.from, p.to,
|
24
|
+
[l.from, p.to, l.to, l.cost+p.cost]
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -43,11 +43,11 @@ program.link <= [['a', 'b', 1],
|
|
43
43
|
['d', 'e', 1]]
|
44
44
|
|
45
45
|
program.tick # one timestamp is enough for this simple program
|
46
|
-
program.shortest.sort.each {|t| puts t.inspect}
|
46
|
+
program.shortest.to_a.sort.each {|t| puts t.inspect}
|
47
47
|
|
48
48
|
puts "----"
|
49
49
|
|
50
50
|
# now lets add an extra link and recompute
|
51
51
|
program.link << ['e', 'f', 1]
|
52
52
|
program.tick
|
53
|
-
program.shortest.sort.each {|t| puts t.inspect}
|
53
|
+
program.shortest.to_a.sort.each {|t| puts t.inspect}
|
data/lib/bud/aggs.rb
CHANGED
@@ -11,7 +11,7 @@ module Bud
|
|
11
11
|
# a. :ignore tells the caller to ignore this input
|
12
12
|
# b. :keep tells the caller to save this input
|
13
13
|
# c. :replace tells the caller to keep this input alone
|
14
|
-
# d.
|
14
|
+
# d. :delete, [t1, t2, ...] tells the caller to delete the remaining tuples
|
15
15
|
# For things that do not descend from ArgExemplary, the 2nd part can simply be nil.
|
16
16
|
def trans(the_state, val)
|
17
17
|
return the_state, :ignore
|
@@ -42,6 +42,8 @@ module Bud
|
|
42
42
|
def trans(the_state, val)
|
43
43
|
if the_state < val
|
44
44
|
return the_state, :ignore
|
45
|
+
elsif the_state == val
|
46
|
+
return the_state, :keep
|
45
47
|
else
|
46
48
|
return val, :replace
|
47
49
|
end
|
@@ -86,41 +88,35 @@ module Bud
|
|
86
88
|
def choose(x)
|
87
89
|
[Choose.new, x]
|
88
90
|
end
|
89
|
-
|
90
|
-
class
|
91
|
-
|
92
|
-
|
93
|
-
the_state = {:cnt => 1, :vals => [x]}
|
91
|
+
|
92
|
+
class ChooseOneRand < ArgExemplary #:nodoc: all
|
93
|
+
def init(x=nil) # Vitter's reservoir sampling, sample size = 1
|
94
|
+
the_state = {:cnt => 1, :val => x}
|
94
95
|
end
|
95
96
|
|
96
97
|
def trans(the_state, val)
|
97
98
|
the_state[:cnt] += 1
|
98
|
-
|
99
|
-
|
100
|
-
|
99
|
+
j = rand(the_state[:cnt])
|
100
|
+
if j < 1 # replace
|
101
|
+
old_val = the_state[:val]
|
102
|
+
the_state[:val] = val
|
103
|
+
return the_state, :replace
|
101
104
|
else
|
102
|
-
|
103
|
-
if j < @@reservoir_size
|
104
|
-
old_tup = the_state[:vals][j]
|
105
|
-
the_state[:vals][j] = val
|
106
|
-
return the_state, [:delete, old_tup]
|
107
|
-
else
|
108
|
-
return the_state, :keep
|
109
|
-
end
|
105
|
+
return the_state, :ignore
|
110
106
|
end
|
111
107
|
end
|
112
108
|
def tie(the_state, val)
|
113
109
|
true
|
114
110
|
end
|
115
111
|
def final(the_state)
|
116
|
-
the_state[:
|
112
|
+
the_state[:val] # XXX rand(@@reservoir_size will always be 0, since @@reservoir_size is 1
|
117
113
|
end
|
118
114
|
end
|
119
115
|
|
120
116
|
# exemplary aggregate method to be used in Bud::BudCollection.group.
|
121
117
|
# randomly chooses among x entries being aggregated.
|
122
118
|
def choose_rand(x=nil)
|
123
|
-
[
|
119
|
+
[ChooseOneRand.new, x]
|
124
120
|
end
|
125
121
|
|
126
122
|
class Sum < Agg #:nodoc: all
|
data/lib/bud/bud_meta.rb
CHANGED
@@ -1,66 +1,45 @@
|
|
1
1
|
require 'bud/rewrite'
|
2
|
-
require 'bud/state'
|
3
|
-
require 'parse_tree'
|
4
2
|
require 'pp'
|
5
3
|
|
6
|
-
class BudMeta #:nodoc: all
|
7
|
-
attr_reader :depanalysis
|
8
4
|
|
5
|
+
class BudMeta #:nodoc: all
|
9
6
|
def initialize(bud_instance, declarations)
|
10
7
|
@bud_instance = bud_instance
|
11
8
|
@declarations = declarations
|
9
|
+
@dependency_analysis = nil # the results of bud_meta are analyzed further using a helper bloom instance. See depanalysis())
|
12
10
|
end
|
13
11
|
|
14
12
|
def meta_rewrite
|
15
|
-
shred_rules
|
16
|
-
top_stratum = stratify
|
17
|
-
stratum_map = binaryrel2map(@bud_instance.t_stratum)
|
18
|
-
|
19
|
-
rewritten_strata = Array.new(top_stratum + 2) { [] }
|
20
|
-
no_attr_rewrite_strata = Array.new(top_stratum + 2) { [] }
|
21
|
-
@bud_instance.t_rules.each do |d|
|
22
|
-
if d.op.to_s == '<='
|
23
|
-
# Deductive rules are assigned to strata based on the basic Datalog
|
24
|
-
# stratification algorithm
|
25
|
-
belongs_in = stratum_map[d.lhs]
|
26
|
-
belongs_in ||= 0
|
27
|
-
rewritten_strata[belongs_in] << d.src
|
28
|
-
no_attr_rewrite_strata[belongs_in] << d.orig_src
|
29
|
-
else
|
30
|
-
# All temporal rules are placed in the last stratum
|
31
|
-
rewritten_strata[top_stratum + 1] << d.src
|
32
|
-
no_attr_rewrite_strata[top_stratum + 1] << d.orig_src
|
33
|
-
end
|
34
|
-
end
|
13
|
+
shred_rules # capture dependencies, rewrite rules
|
35
14
|
|
36
|
-
|
37
|
-
@bud_instance.
|
38
|
-
|
39
|
-
3.times { @depanalysis.tick_internal }
|
15
|
+
stratified_rules = []
|
16
|
+
if @bud_instance.toplevel == @bud_instance
|
17
|
+
nodes, stratum_map, top_stratum = stratify_preds
|
40
18
|
|
41
|
-
|
42
|
-
puts "Warning: underspecified dataflow: #{u.inspect}"
|
43
|
-
@bud_instance.t_underspecified << u
|
44
|
-
end
|
45
|
-
@depanalysis.source.each do |s|
|
46
|
-
@bud_instance.sources[s.first] = true
|
47
|
-
end
|
48
|
-
@depanalysis.sink.each do |s|
|
49
|
-
@bud_instance.sinks[s.first] = true
|
50
|
-
end
|
51
|
-
|
52
|
-
dump_rewrite(no_attr_rewrite_strata) if @bud_instance.options[:dump_rewrite]
|
19
|
+
# stratum_map = {fully qualified pred => stratum}
|
53
20
|
|
54
|
-
|
55
|
-
|
21
|
+
#slot each rule into the stratum corresponding to its lhs pred (from stratum_map)
|
22
|
+
stratified_rules = Array.new(top_stratum + 2) { [] } # stratum -> [ rules ]
|
23
|
+
@bud_instance.t_rules.each do |rule|
|
24
|
+
if rule.op.to_s == '<='
|
25
|
+
# Deductive rules are assigned to strata based on the basic Datalog
|
26
|
+
# stratification algorithm
|
27
|
+
belongs_in = stratum_map[rule.lhs]
|
28
|
+
belongs_in ||= 0
|
29
|
+
stratified_rules[belongs_in] << rule
|
30
|
+
else
|
31
|
+
# All temporal rules are placed in the last stratum
|
32
|
+
stratified_rules[top_stratum + 1] << rule
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# stratified_rules[0] may be empty if none of the nodes at stratum 0 are on the lhs
|
36
|
+
# stratified_rules[top_stratum+1] will be empty if there are no temporal rules.
|
37
|
+
# Cleanup
|
38
|
+
stratified_rules = stratified_rules.reject{|r| r.empty?}
|
39
|
+
dump_rewrite(stratified_rules) if @bud_instance.options[:dump_rewrite]
|
56
40
|
|
57
|
-
def binaryrel2map(rel)
|
58
|
-
map = {}
|
59
|
-
rel.each do |s|
|
60
|
-
raise Bud::Error unless s.length == 2
|
61
|
-
map[s[0]] = s[1]
|
62
41
|
end
|
63
|
-
return
|
42
|
+
return stratified_rules
|
64
43
|
end
|
65
44
|
|
66
45
|
def shred_rules
|
@@ -87,11 +66,18 @@ class BudMeta #:nodoc: all
|
|
87
66
|
end
|
88
67
|
|
89
68
|
def rewrite_rule_block(klass, block_name, seed)
|
90
|
-
|
91
|
-
return unless parse_tree.first
|
69
|
+
return unless klass.respond_to? :__bloom_asts__
|
92
70
|
|
93
|
-
pt =
|
71
|
+
pt = klass.__bloom_asts__[block_name]
|
72
|
+
return if pt.nil?
|
73
|
+
|
74
|
+
pt = Marshal.load(Marshal.dump(pt)) #deep clone because RuleRewriter mucks up pt.
|
94
75
|
pp pt if @bud_instance.options[:dump_ast]
|
76
|
+
tmp_expander = TempExpander.new
|
77
|
+
pt = tmp_expander.process(pt)
|
78
|
+
tmp_expander.tmp_tables.each do |t|
|
79
|
+
@bud_instance.temp(t.to_sym)
|
80
|
+
end
|
95
81
|
|
96
82
|
rv = check_rule_ast(pt)
|
97
83
|
unless rv.nil?
|
@@ -112,12 +98,30 @@ class BudMeta #:nodoc: all
|
|
112
98
|
end
|
113
99
|
raise Bud::CompileError, "#{error_msg} in rule block \"#{block_name}\"#{src_msg}"
|
114
100
|
end
|
115
|
-
|
116
101
|
rewriter = RuleRewriter.new(seed, @bud_instance)
|
117
102
|
rewriter.process(pt)
|
118
103
|
return rewriter
|
119
104
|
end
|
120
105
|
|
106
|
+
def get_qual_name(pt)
|
107
|
+
# expect to see a parse tree corresponding to a dotted name
|
108
|
+
# a.b.c == s(:call, s1, :c, (:args))
|
109
|
+
# where s1 == s(:call, s2, :b, (:args))
|
110
|
+
# where s2 == s(:call, nil,:a, (:args))
|
111
|
+
|
112
|
+
tag, recv, name, args = pt
|
113
|
+
return nil unless tag == :call or args.length == 1
|
114
|
+
|
115
|
+
if recv
|
116
|
+
qn = get_qual_name(recv)
|
117
|
+
return nil if qn.nil? or qn.size == 0
|
118
|
+
qn = qn + "." + name.to_s
|
119
|
+
else
|
120
|
+
qn = name.to_s
|
121
|
+
end
|
122
|
+
qn
|
123
|
+
end
|
124
|
+
|
121
125
|
# Perform some basic sanity checks on the AST of a rule block. We expect a
|
122
126
|
# rule block to consist of a :defn, a nested :scope, and then a sequence of
|
123
127
|
# statements. Each statement is a :call node. Returns nil (no error found), a
|
@@ -147,10 +151,9 @@ class BudMeta #:nodoc: all
|
|
147
151
|
tag, lhs, op, rhs = n
|
148
152
|
|
149
153
|
# Check that LHS references a named collection
|
150
|
-
|
151
|
-
lhs_name
|
152
|
-
|
153
|
-
return [n, "collection does not exist: '#{lhs_name}'"]
|
154
|
+
lhs_name = get_qual_name(lhs)
|
155
|
+
unless lhs_name and @bud_instance.tables.has_key? lhs_name.to_sym
|
156
|
+
return [n, "Collection does not exist: '#{lhs_name}'"]
|
154
157
|
end
|
155
158
|
|
156
159
|
return [n, "illegal operator: '#{op}'"] unless [:<, :<=].include? op
|
@@ -176,36 +179,121 @@ class BudMeta #:nodoc: all
|
|
176
179
|
return nil # No errors found
|
177
180
|
end
|
178
181
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
@bud_instance.
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
182
|
+
|
183
|
+
Node = Struct.new :name, :status, :stratum, :edges, :in_lhs, :in_body, :in_cycle, :is_neg_head
|
184
|
+
# Node.status is one of :init, :in_progress, :done
|
185
|
+
Edge = Struct.new :to, :op, :neg, :temporal
|
186
|
+
|
187
|
+
def stratify_preds
|
188
|
+
bud = @bud_instance.toplevel
|
189
|
+
nodes = {}
|
190
|
+
bud.t_depends.each do |d|
|
191
|
+
#t_depends [:bud_instance, :rule_id, :lhs, :op, :body] => [:nm]
|
192
|
+
lhs = (nodes[d.lhs.to_s] ||= Node.new(d.lhs.to_s, :init, 0, [], true, false, false, false))
|
193
|
+
lhs.in_lhs = true
|
194
|
+
body = (nodes[d.body.to_s] ||= Node.new(d.body.to_s, :init, 0, [], false, true, false, false))
|
195
|
+
temporal = d.op != "<="
|
196
|
+
lhs.edges << Edge.new(body, d.op, d.nm, temporal)
|
197
|
+
body.in_body = true
|
190
198
|
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
199
|
+
|
200
|
+
nodes.values.each {|n| calc_stratum(n, false, false, [n.name])}
|
201
|
+
# Normalize stratum numbers because they may not be 0-based or consecutive
|
202
|
+
remap = {}
|
203
|
+
# if the nodes stratum numbers are [2, 3, 2, 4], remap = {2 => 0, 3 => 1, 4 => 2}
|
204
|
+
nodes.values.map {|n| n.stratum}.uniq.sort.each_with_index{|num, i|
|
205
|
+
remap[num] = i
|
206
|
+
}
|
207
|
+
stratum_map = {}
|
208
|
+
top_stratum = -1
|
209
|
+
nodes.each_pair do |name, n|
|
210
|
+
n.stratum = remap[n.stratum]
|
211
|
+
stratum_map[n.name] = n.stratum
|
212
|
+
top_stratum = max(top_stratum, n.stratum)
|
197
213
|
end
|
214
|
+
analyze_dependencies(nodes)
|
215
|
+
return nodes, stratum_map, top_stratum
|
216
|
+
end
|
198
217
|
|
199
|
-
|
218
|
+
def max(a, b) ; a > b ? a : b ; end
|
219
|
+
|
220
|
+
def calc_stratum(node, neg, temporal, path)
|
221
|
+
if node.status == :in_process
|
222
|
+
node.in_cycle = true
|
223
|
+
if neg and !temporal and node.is_neg_head
|
224
|
+
raise Bud::CompileError, "unstratifiable program: #{path.uniq.join(',')}"
|
225
|
+
end
|
226
|
+
elsif node.status == :init
|
227
|
+
node.status = :in_process
|
228
|
+
node.edges.each do |edge|
|
229
|
+
node.is_neg_head = edge.neg
|
230
|
+
next if edge.op != "<="
|
231
|
+
body_stratum = calc_stratum(edge.to, (neg or edge.neg), (edge.temporal or temporal), path + [edge.to.name])
|
232
|
+
node.is_neg_head = false #reset for next edge
|
233
|
+
node.stratum = max(node.stratum, body_stratum + (edge.neg ? 1 : 0))
|
234
|
+
end
|
235
|
+
node.status = :done
|
236
|
+
end
|
237
|
+
node.stratum
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
def analyze_dependencies(nodes) # nodes = {node name => node}
|
242
|
+
bud = @bud_instance
|
243
|
+
|
244
|
+
preds_in_lhs = nodes.inject(Set.new) {|preds, name_n| preds.add(name_n[0]) if name_n[1].in_lhs; preds}
|
245
|
+
preds_in_body = nodes.inject(Set.new) {|preds, name_n| preds.add(name_n[0]) if name_n[1].in_body; preds}
|
246
|
+
|
247
|
+
bud.t_provides.each do |p|
|
248
|
+
pred, input = p.interface, p.input
|
249
|
+
if input
|
250
|
+
# an interface pred is a source if it is an input and it is not in any rule's lhs
|
251
|
+
#bud.sources << [pred] unless (preds_in_lhs.include? pred)
|
252
|
+
unless preds_in_body.include? pred.to_s
|
253
|
+
# input interface is underspecified if not used in any rule body
|
254
|
+
bud.t_underspecified << [pred, true] # true indicates input mode
|
255
|
+
puts "Warning: input interface #{pred} not used"
|
256
|
+
end
|
257
|
+
else
|
258
|
+
# an interface pred is a sink if it is not an input and it is not in any rule's body
|
259
|
+
#(if it is in the body, then it is an intermediate node feeding some lhs)
|
260
|
+
#bud.sinks << [pred] unless (preds_in_body.include? pred)
|
261
|
+
unless preds_in_lhs.include? pred.to_s
|
262
|
+
# output interface underspecified if not in any rule's lhs
|
263
|
+
bud.t_underspecified << [pred, false] #false indicates output mode.
|
264
|
+
puts "Warning: output interface #{pred} not used"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def depanalysis
|
271
|
+
if @dependency_analysis.nil?
|
272
|
+
require 'bud/depanalysis'
|
273
|
+
da = ::DepAnalysis.new
|
274
|
+
da.providing <+ @bud_instance.tables[:t_provides].to_a
|
275
|
+
da.depends <+ @bud_instance.t_depends.map{|d| [d.lhs, d.op, d.body, d.nm]}
|
276
|
+
|
277
|
+
#@bud_instance.tables[:t_provides].each {|t| da.providing <+ t}
|
278
|
+
#@bud_instance.tables[:t_depends].each {|t| da.depends_tc <+ t}
|
279
|
+
da.tick_internal
|
280
|
+
@dependency_analysis = da
|
281
|
+
end
|
282
|
+
@dependency_analysis
|
200
283
|
end
|
201
284
|
|
202
285
|
def dump_rewrite(strata)
|
203
286
|
fout = File.new("#{@bud_instance.class}_rewritten.txt", "w")
|
204
287
|
fout.puts "Declarations:"
|
205
288
|
|
206
|
-
strata.each_with_index do |
|
207
|
-
|
208
|
-
fout.
|
289
|
+
strata.each_with_index do |rules, i|
|
290
|
+
fout.print "=================================\n"
|
291
|
+
fout.print "Stratum #{i}\n"
|
292
|
+
rules.each do |r|
|
293
|
+
fout.puts "#{r.bud_obj.class}##{r.bud_obj.object_id} #{r.rule_id}"
|
294
|
+
fout.puts "\tsrc: #{r.src}"
|
295
|
+
fout.puts "\torig src: #{r.orig_src}"
|
296
|
+
end
|
209
297
|
end
|
210
298
|
fout.close
|
211
299
|
end
|
data/lib/bud/bust/bust.rb
CHANGED
@@ -68,23 +68,30 @@ module Bust
|
|
68
68
|
if @request =~ /GET .* HTTP*/
|
69
69
|
puts "GET shouldn't have body" if @body
|
70
70
|
# select the appropriate elements from the table
|
71
|
-
desired_elements =
|
72
|
-
uri_params.all? {|k, v|
|
71
|
+
desired_elements = @bud.send(table_name.to_sym).find_all do |t|
|
72
|
+
uri_params.all? {|k, v|
|
73
|
+
(eval "t." + k.to_s) == v[0]
|
74
|
+
}
|
73
75
|
end
|
74
76
|
@session.print success
|
77
|
+
desired_elements = desired_elements .map{|elem|
|
78
|
+
elem.class <= Struct ? elem.to_a : elem
|
79
|
+
}
|
75
80
|
@session.print desired_elements.to_json
|
76
81
|
elsif @request =~ /POST .* HTTP*/
|
77
82
|
# instantiate a new tuple
|
78
83
|
tuple_to_insert = []
|
79
84
|
@body.each do |k, v|
|
80
|
-
index =
|
85
|
+
index = @bud.send(table_name.to_sym).cols.find_index(k.to_sym)
|
81
86
|
for i in (tuple_to_insert.size..index)
|
82
87
|
tuple_to_insert << nil
|
83
88
|
end
|
84
89
|
tuple_to_insert[index] = v[0]
|
85
90
|
end
|
86
91
|
# actually insert the puppy
|
87
|
-
@bud.async_do {
|
92
|
+
@bud.async_do {
|
93
|
+
@bud.send(table_name.to_sym) <+ [tuple_to_insert]
|
94
|
+
}
|
88
95
|
@session.print success
|
89
96
|
end
|
90
97
|
rescue Exception
|