bud 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -1
- data/docs/cheat.md +3 -3
- data/examples/{README → README.md} +0 -0
- data/lib/bud/bud_meta.rb +21 -13
- data/lib/bud/collections.rb +123 -130
- data/lib/bud/executor/elements.rb +27 -52
- data/lib/bud/executor/group.rb +1 -1
- data/lib/bud/executor/join.rb +7 -12
- data/lib/bud/rewrite.rb +83 -53
- data/lib/bud/storage/dbm.rb +2 -2
- data/lib/bud/viz_util.rb +4 -2
- data/lib/bud.rb +21 -7
- metadata +27 -68
- data/docs/bust.md +0 -83
- data/examples/bust/README.md +0 -9
- data/examples/bust/bustclient-example.rb +0 -23
- data/examples/bust/bustinspector.html +0 -135
- data/examples/bust/bustserver-example.rb +0 -18
- data/lib/bud/bust/bust.rb +0 -137
- data/lib/bud/bust/client/idempotence.rb +0 -10
- data/lib/bud/bust/client/restclient.rb +0 -49
@@ -13,9 +13,9 @@ module Bud
|
|
13
13
|
# p.insert(1)
|
14
14
|
# p.insert(nil)
|
15
15
|
class PushElement < BudCollection
|
16
|
-
attr_accessor :elem_name
|
17
16
|
attr_accessor :rescan, :invalidated
|
18
|
-
|
17
|
+
attr_accessor :elem_name
|
18
|
+
attr_reader :found_delta, :refcount, :wired_by, :outputs
|
19
19
|
|
20
20
|
def initialize(name_in, bud_instance, collection_name=nil, given_schema=nil, defer_schema=false, &blk)
|
21
21
|
super(name_in, bud_instance, given_schema, defer_schema)
|
@@ -33,10 +33,6 @@ module Bud
|
|
33
33
|
@rescan = true
|
34
34
|
end
|
35
35
|
|
36
|
-
def wiring?
|
37
|
-
@bud_instance.toplevel.done_wiring == false
|
38
|
-
end
|
39
|
-
|
40
36
|
def wirings
|
41
37
|
@wirings ||= @outputs + @pendings + @deletes + @delete_keys
|
42
38
|
end
|
@@ -81,40 +77,27 @@ module Bud
|
|
81
77
|
def set_block(&blk)
|
82
78
|
@blk = blk
|
83
79
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
# elem_name = element.respond_to?(:tabname) ? element.tabname : element.elem_name
|
89
|
-
# puts "wiring #{self.elem_name} to #{elem_name}"
|
90
|
-
@outputs << element
|
91
|
-
element.wired_by << self if element.respond_to? :wired_by
|
92
|
-
end
|
93
|
-
def wire_to_pending(element)
|
94
|
-
unless element.respond_to? :pending_merge
|
95
|
-
raise Bud::Error, "attempt to wire_to_pending element without pending_merge method"
|
96
|
-
end
|
97
|
-
# elem_name = element.respond_to?(:tabname) ? element.tabname : element.elem_name
|
98
|
-
# puts "wiring #{self.elem_name} to #{elem_name}(pending)"
|
99
|
-
@pendings << element
|
100
|
-
element.wired_by << self if element.respond_to? :wired_by
|
101
|
-
end
|
102
|
-
def wire_to_delete(element)
|
103
|
-
unless element.respond_to? :pending_delete
|
104
|
-
raise Bud::Error, "attempt to wire_to_delete element without pending_delete method"
|
80
|
+
|
81
|
+
def wire_to(element, kind=:output)
|
82
|
+
unless @bud_instance.wiring?
|
83
|
+
raise Bud::Error, "wire_to called outside wiring phase"
|
105
84
|
end
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
85
|
+
|
86
|
+
case kind
|
87
|
+
when :output
|
88
|
+
raise Bud::Error unless element.respond_to? :insert
|
89
|
+
@outputs << element
|
90
|
+
when :pending
|
91
|
+
raise Bud::Error unless element.respond_to? :pending_merge
|
92
|
+
@pendings << element
|
93
|
+
when :delete
|
94
|
+
raise Bud::Error unless element.respond_to? :pending_delete
|
95
|
+
@deletes << element
|
96
|
+
when :delete_by_key
|
97
|
+
raise Bud::Error unless element.respond_to? :pending_delete_keys
|
98
|
+
@delete_keys << element
|
114
99
|
end
|
115
|
-
|
116
|
-
# puts "wiring #{self.elem_name} to #{elem_name}(delete)"
|
117
|
-
@delete_keys << element
|
100
|
+
|
118
101
|
element.wired_by << self if element.respond_to? :wired_by
|
119
102
|
end
|
120
103
|
|
@@ -144,12 +127,8 @@ module Bud
|
|
144
127
|
unless item.nil?
|
145
128
|
@outputs.each do |ou|
|
146
129
|
if ou.class <= Bud::PushElement
|
147
|
-
#the_name = ou.elem_name
|
148
|
-
# puts "#{self.object_id%10000} (#{elem_name}) -> #{ou.object_id%10000} (#{the_name}): #{item.inspect}"
|
149
130
|
ou.insert(item, self)
|
150
131
|
elsif ou.class <= Bud::BudCollection
|
151
|
-
# the_name = ou.tabname
|
152
|
-
# puts "#{self.object_id%10000} (#{elem_name}) -> #{ou.object_id%10000} (#{the_name}): #{item.inspect}"
|
153
132
|
ou.do_insert(item, ou.new_delta)
|
154
133
|
else
|
155
134
|
raise Bud::Error, "expected either a PushElement or a BudCollection"
|
@@ -210,19 +189,14 @@ module Bud
|
|
210
189
|
public
|
211
190
|
def stratum_end
|
212
191
|
end
|
213
|
-
#public
|
214
|
-
#def set_schema(schema)
|
215
|
-
# @schema=schema
|
216
|
-
# setup_accessors
|
217
|
-
#end
|
218
|
-
|
219
192
|
|
220
193
|
####
|
221
194
|
# and now, the Bloom-facing methods
|
195
|
+
# XXX: "the_name" parameter is unused
|
222
196
|
public
|
223
|
-
def pro(the_name
|
197
|
+
def pro(the_name=elem_name, the_schema=schema, &blk)
|
224
198
|
toplevel = @bud_instance.toplevel
|
225
|
-
elem = Bud::PushElement.new(
|
199
|
+
elem = Bud::PushElement.new("project#{object_id}",
|
226
200
|
toplevel.this_rule_context,
|
227
201
|
@collection_name, the_schema)
|
228
202
|
self.wire_to(elem)
|
@@ -233,10 +207,11 @@ module Bud
|
|
233
207
|
|
234
208
|
alias each pro
|
235
209
|
|
210
|
+
# XXX: "the_name" & "the_schema" parameters are unused
|
236
211
|
public
|
237
212
|
def each_with_index(the_name=elem_name, the_schema=schema, &blk)
|
238
213
|
toplevel = @bud_instance.toplevel
|
239
|
-
elem = Bud::PushEachWithIndex.new(
|
214
|
+
elem = Bud::PushEachWithIndex.new("each_with_index#{object_id}",
|
240
215
|
toplevel.this_rule_context,
|
241
216
|
@collection_name)
|
242
217
|
elem.set_block(&blk)
|
@@ -273,7 +248,7 @@ module Bud
|
|
273
248
|
end
|
274
249
|
|
275
250
|
def merge(source)
|
276
|
-
if source.class <= PushElement and wiring?
|
251
|
+
if source.class <= PushElement and @bud_instance.wiring?
|
277
252
|
source.wire_to(self)
|
278
253
|
else
|
279
254
|
source.each {|i| self << i}
|
data/lib/bud/executor/group.rb
CHANGED
@@ -46,7 +46,7 @@ module Bud
|
|
46
46
|
|
47
47
|
class PushArgAgg < PushGroup
|
48
48
|
def initialize(elem_name, bud_instance, collection_name, keys_in, aggpairs_in, schema_in, &blk)
|
49
|
-
raise "
|
49
|
+
raise Bud::Error, "multiple aggpairs #{aggpairs_in.map{|a| a.class.name}} in ArgAgg; only one allowed" if aggpairs_in.length > 1
|
50
50
|
super(elem_name, bud_instance, collection_name, keys_in, aggpairs_in, schema_in, &blk)
|
51
51
|
@agg = @aggpairs[0][0]
|
52
52
|
@aggcol = @aggpairs[0][1]
|
data/lib/bud/executor/join.rb
CHANGED
@@ -16,7 +16,6 @@ module Bud
|
|
16
16
|
@selfjoins = []
|
17
17
|
@input_bufs = [[],[]]
|
18
18
|
@missing_keys = Set.new
|
19
|
-
the_join = nil
|
20
19
|
|
21
20
|
# if any elements on rellist are PushSHJoins, suck up their contents
|
22
21
|
@all_rels_below = []
|
@@ -24,7 +23,6 @@ module Bud
|
|
24
23
|
if r.class <= PushSHJoin
|
25
24
|
@all_rels_below += r.all_rels_below
|
26
25
|
preds += r.origpreds
|
27
|
-
the_join = r
|
28
26
|
else
|
29
27
|
@all_rels_below << r
|
30
28
|
end
|
@@ -85,8 +83,7 @@ module Bud
|
|
85
83
|
# extract predicates on rellist[1] and recurse to left side with remainder
|
86
84
|
protected
|
87
85
|
def setup_preds(preds) # :nodoc: all
|
88
|
-
|
89
|
-
# print "setting up preds for #{@relnames.inspect}(#{self.object_id}): "
|
86
|
+
# print "setting up preds for #{@relnames.inspect}(#{self.object_id}): "
|
90
87
|
allpreds = disambiguate_preds(preds)
|
91
88
|
allpreds = canonicalize_localpreds(@rels, allpreds)
|
92
89
|
# check for refs to collections that aren't being joined, Issue 191
|
@@ -135,7 +132,7 @@ module Bud
|
|
135
132
|
else
|
136
133
|
@keys = []
|
137
134
|
end
|
138
|
-
|
135
|
+
# puts "@keys = #{@keys.inspect}"
|
139
136
|
end
|
140
137
|
|
141
138
|
public
|
@@ -301,7 +298,7 @@ module Bud
|
|
301
298
|
offsets.each do |offset|
|
302
299
|
buf = @input_bufs[offset]
|
303
300
|
buf << item
|
304
|
-
if
|
301
|
+
if buf.length >= ELEMENT_BUFSIZE
|
305
302
|
flush_buf(buf, offset)
|
306
303
|
end
|
307
304
|
end
|
@@ -309,7 +306,7 @@ module Bud
|
|
309
306
|
|
310
307
|
protected
|
311
308
|
def insert_item(item, offset)
|
312
|
-
if
|
309
|
+
if @keys.nil? or @keys.empty?
|
313
310
|
the_key = nil
|
314
311
|
else
|
315
312
|
# assumes left-deep trees
|
@@ -337,7 +334,6 @@ module Bud
|
|
337
334
|
|
338
335
|
public
|
339
336
|
def add_rescan_invalidate(rescan, invalidate)
|
340
|
-
|
341
337
|
if non_temporal_predecessors.any? {|e| rescan.member? e}
|
342
338
|
rescan << self
|
343
339
|
invalidate << self
|
@@ -450,7 +446,6 @@ module Bud
|
|
450
446
|
self.extend(Bud::PushSHOuterJoin)
|
451
447
|
end
|
452
448
|
|
453
|
-
|
454
449
|
public
|
455
450
|
def rights(*preds, &blk)
|
456
451
|
@cols = blk.nil? ? @bud_instance.tables[@rels[1].tabname].cols : nil
|
@@ -535,7 +530,7 @@ module Bud
|
|
535
530
|
|
536
531
|
private
|
537
532
|
def insert_item(item, offset)
|
538
|
-
if
|
533
|
+
if @keys.nil? or @keys.empty?
|
539
534
|
the_key = nil
|
540
535
|
else
|
541
536
|
if all_rels_below.length > 2 and offset == 1
|
@@ -571,7 +566,7 @@ module Bud
|
|
571
566
|
if @missing_keys
|
572
567
|
@missing_keys.each do |key|
|
573
568
|
@hash_tables[0][key].each do |t|
|
574
|
-
push_out([t, []])
|
569
|
+
push_out([t, @rels[1].null_tuple])
|
575
570
|
end
|
576
571
|
end
|
577
572
|
end
|
@@ -580,7 +575,7 @@ module Bud
|
|
580
575
|
|
581
576
|
class PushNotIn < PushSHJoin
|
582
577
|
def initialize(rellist, bud_instance, preds=nil, &blk) # :nodoc: all
|
583
|
-
if
|
578
|
+
if preds.nil? or preds.empty?
|
584
579
|
preds = positionwise_preds(bud_instance, rellist)
|
585
580
|
end
|
586
581
|
super(rellist, bud_instance, preds)
|
data/lib/bud/rewrite.rb
CHANGED
@@ -1,21 +1,20 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'ruby2ruby'
|
3
|
+
require 'set'
|
3
4
|
|
4
5
|
class RuleRewriter < Ruby2Ruby # :nodoc: all
|
5
6
|
attr_accessor :rule_indx, :rules, :depends
|
6
7
|
|
8
|
+
OP_LIST = Set.new([:<<, :<, :<=])
|
9
|
+
TEMP_OP_LIST = Set.new([:-@, :~, :+@])
|
10
|
+
MONOTONE_WHITELIST = Set.new([:==, :+, :<=, :-, :<, :>, :*, :~,
|
11
|
+
:pairs, :matches, :combos, :flatten,
|
12
|
+
:lefts, :rights, :map, :flat_map, :pro,
|
13
|
+
:cols, :key_cols, :val_cols, :payloads, :lambda,
|
14
|
+
:tabname, :ip_port, :port, :ip, :int_ip_port])
|
15
|
+
|
7
16
|
def initialize(seed, bud_instance)
|
8
17
|
@bud_instance = bud_instance
|
9
|
-
@ops = {:<< => 1, :< => 1, :<= => 1}
|
10
|
-
@monotonic_whitelist = {
|
11
|
-
:== => 1, :+ => 1, :<= => 1, :- => 1, :< => 1, :> => 1,
|
12
|
-
:* => 1, :pairs => 1, :matches => 1, :combos => 1, :flatten => 1,
|
13
|
-
:lefts => 1, :rights => 1, :map => 1, :flat_map => 1, :pro => 1,
|
14
|
-
:cols => 1, :key_cols => 1, :val_cols => 1, :payloads => 1, :~ => 1,
|
15
|
-
:lambda => 1, :tabname => 1,
|
16
|
-
:ip_port => 1, :port => 1, :ip => 1
|
17
|
-
}
|
18
|
-
@temp_ops = {:-@ => 1, :~ => 1, :+@ => 1}
|
19
18
|
@tables = {}
|
20
19
|
@nm = false
|
21
20
|
@rule_indx = seed
|
@@ -29,7 +28,7 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
29
28
|
$not_id = [:not_coll_id]
|
30
29
|
def resolve(obj, prefix, name)
|
31
30
|
qn = prefix ? prefix + "." + name.to_s : name.to_s
|
32
|
-
return [:collection, qn, obj.tables[name]]
|
31
|
+
return [:collection, qn, obj.tables[name]] if obj.tables.has_key? name
|
33
32
|
|
34
33
|
# does name refer to an import name?
|
35
34
|
iobj = obj.import_instance name
|
@@ -56,60 +55,72 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
56
55
|
|
57
56
|
def process_call(exp)
|
58
57
|
recv, op, args = exp
|
59
|
-
if
|
58
|
+
if OP_LIST.include?(op) and @context[1] == :block and @context.length == 4
|
60
59
|
# NB: context.length is 4 when see a method call at the top-level of a
|
61
60
|
# :defn block -- this is where we expect Bloom statements to appear
|
62
61
|
do_rule(exp)
|
63
62
|
else
|
64
|
-
ty =
|
65
|
-
ty, qn, obj = exp_id_type(recv, op, args) # qn = qualified name, obj is the corresponding object
|
63
|
+
ty, qn, _ = exp_id_type(recv, op, args) # qn = qualified name
|
66
64
|
if ty == :collection
|
67
65
|
@tables[qn] = @nm if @collect
|
68
66
|
#elsif ty == :import .. do nothing
|
69
67
|
elsif ty == :not_coll_id
|
70
|
-
# check if receiver is a collection, and further if the current exp
|
68
|
+
# check if receiver is a collection, and further if the current exp
|
69
|
+
# represents a field lookup
|
71
70
|
op_is_field_name = false
|
72
71
|
if recv and recv.first == :call
|
73
72
|
rty, _, robj = exp_id_type(recv[1], recv[2], recv[3])
|
74
73
|
if rty == :collection
|
75
74
|
cols = robj.cols
|
76
|
-
op_is_field_name =
|
75
|
+
op_is_field_name = true if cols and cols.include?(op)
|
77
76
|
end
|
78
77
|
end
|
79
78
|
# for CALM analysis, mark deletion rules as non-monotonic
|
80
79
|
@nm = true if op == :-@
|
81
80
|
if recv
|
82
|
-
# don't worry about monotone ops, table names, table.attr calls, or
|
83
|
-
|
84
|
-
|
81
|
+
# don't worry about monotone ops, table names, table.attr calls, or
|
82
|
+
# accessors of iterator variables
|
83
|
+
unless RuleRewriter.is_monotone(op) or op_is_field_name or
|
84
|
+
recv.first == :lvar or op.to_s.start_with?("__")
|
85
|
+
@nm = true
|
85
86
|
end
|
86
87
|
else
|
87
|
-
# function called (implicit receiver = Bud instance) in a user-defined
|
88
|
-
# non-monotonic (like budtime, that
|
89
|
-
|
88
|
+
# function called (implicit receiver = Bud instance) in a user-defined
|
89
|
+
# code block. Check if it is non-monotonic (like budtime, that
|
90
|
+
# produces a new value every time it is called)
|
91
|
+
@nm_funcs_called = true unless RuleRewriter.is_monotone(op)
|
90
92
|
end
|
91
93
|
end
|
92
|
-
if
|
94
|
+
if TEMP_OP_LIST.include? op
|
93
95
|
@temp_op = op.to_s.gsub("@", "")
|
94
96
|
end
|
95
97
|
super
|
96
98
|
end
|
97
99
|
end
|
98
100
|
|
101
|
+
def self.is_monotone(op)
|
102
|
+
MONOTONE_WHITELIST.include?(op)
|
103
|
+
end
|
104
|
+
|
105
|
+
# rewrite constant array expressions to lambdas
|
106
|
+
def lambda_rewrite(rhs)
|
107
|
+
# the <= case
|
108
|
+
if rhs[0] == :array
|
109
|
+
return s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, rhs)
|
110
|
+
# the superator case
|
111
|
+
elsif rhs[0] == :call \
|
112
|
+
and rhs[1] and rhs[1][0] and rhs[1][0] == :array \
|
113
|
+
and rhs[2] and (rhs[2] == :+@ or rhs[2] == :-@ or rhs[2] == :~@)
|
114
|
+
return s(rhs[0], s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, rhs[1]), rhs[2], rhs[3])
|
115
|
+
else
|
116
|
+
return rhs
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
99
120
|
def collect_rhs(exp)
|
121
|
+
exp = lambda_rewrite(exp)
|
122
|
+
|
100
123
|
@collect = true
|
101
|
-
# rewrite constant array expressions to lambdas
|
102
|
-
if exp[0] and exp[0] == :arglist
|
103
|
-
# the <= case
|
104
|
-
if exp[1] and exp[1][0] == :array
|
105
|
-
exp = s(exp[0], s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, exp[1]))
|
106
|
-
# the superator case
|
107
|
-
elsif exp[1] and exp[1][0] == :call \
|
108
|
-
and exp[1][1] and exp[1][1][0] and exp[1][1][0] == :array \
|
109
|
-
and exp[1][2] and (exp[1][2] == :+@ or exp[1][2] == :-@ or exp[1][2] == :~@)
|
110
|
-
exp = s(exp[0], s(exp[1][0], s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, exp[1][1]), exp[1][2], exp[1][3]))
|
111
|
-
end
|
112
|
-
end
|
113
124
|
rhs = process exp
|
114
125
|
@collect = false
|
115
126
|
return rhs
|
@@ -132,8 +143,8 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
132
143
|
end
|
133
144
|
|
134
145
|
@rules << [@bud_instance, @rule_indx, lhs, op, rule_txt, rule_txt_orig, @nm_funcs_called]
|
135
|
-
@tables.each_pair do |t,
|
136
|
-
@depends << [@bud_instance, @rule_indx, lhs, op, t,
|
146
|
+
@tables.each_pair do |t, nm|
|
147
|
+
@depends << [@bud_instance, @rule_indx, lhs, op, t, nm]
|
137
148
|
end
|
138
149
|
|
139
150
|
reset_instance_vars
|
@@ -149,7 +160,9 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
149
160
|
# s(:arglist) is not really sensible and it causes Ruby2Ruby < 1.3.1 to
|
150
161
|
# misbehave (for example, s(:arglist, s(:hash, ...)) is misparsed.
|
151
162
|
raise Bud::CompileError unless rhs_ast.sexp_type == :arglist
|
152
|
-
|
163
|
+
rhs_ast = rhs_ast[1]
|
164
|
+
|
165
|
+
rhs_ast = RenameRewriter.new(@bud_instance).process(rhs_ast)
|
153
166
|
|
154
167
|
if @bud_instance.options[:no_attr_rewrite]
|
155
168
|
rhs = collect_rhs(rhs_ast)
|
@@ -191,6 +204,37 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
191
204
|
end
|
192
205
|
end
|
193
206
|
|
207
|
+
# Look for rename statements and define the necessary scratch collections
|
208
|
+
class RenameRewriter < SexpProcessor
|
209
|
+
def initialize(bud_instance)
|
210
|
+
super()
|
211
|
+
self.require_empty = false
|
212
|
+
self.expected = Sexp
|
213
|
+
@bud_instance = bud_instance
|
214
|
+
end
|
215
|
+
|
216
|
+
def register_scratch(name, schemahash)
|
217
|
+
# define a scratch with the name and schema in this rename block
|
218
|
+
hash, key_array, val_array = schemahash
|
219
|
+
key_array ||= []
|
220
|
+
val_array ||= []
|
221
|
+
key_cols = key_array.map{|i| i[1] if i.class <= Sexp}.compact
|
222
|
+
val_cols = val_array.map{|i| i[1] if i.class <= Sexp}.compact
|
223
|
+
@bud_instance.scratch(name, key_cols=>val_cols)
|
224
|
+
end
|
225
|
+
|
226
|
+
def process_call(exp)
|
227
|
+
call, recv, op, args = exp
|
228
|
+
|
229
|
+
if op == :rename
|
230
|
+
arglist, namelit, schemahash = args
|
231
|
+
register_scratch(namelit[1], schemahash)
|
232
|
+
end
|
233
|
+
|
234
|
+
return s(call, process(recv), op, process(args))
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
194
238
|
# Rewrite named-column refs to positional refs
|
195
239
|
class AttrNameRewriter < SexpProcessor # :nodoc: all
|
196
240
|
def initialize(bud_instance)
|
@@ -225,7 +269,7 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
225
269
|
return unless exp[2][1] and exp[2][1][0] == :array
|
226
270
|
if exp[1][2] == :reduce
|
227
271
|
unless @collnames.length == 1
|
228
|
-
raise Bud::Error, "reduce should only one associated collection, but has #{@collnames.inspect}"
|
272
|
+
raise Bud::Error, "reduce should only have one associated collection, but has #{@collnames.inspect}"
|
229
273
|
end
|
230
274
|
@iterhash[exp[2][1][2][1]] = @collnames.first
|
231
275
|
else #join
|
@@ -240,16 +284,6 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
240
284
|
exp
|
241
285
|
end
|
242
286
|
|
243
|
-
def register_scratch(name, schemahash)
|
244
|
-
# define a scratch with the name and schema in this rename block
|
245
|
-
hash, key_array, val_array = schemahash
|
246
|
-
key_array ||= []
|
247
|
-
val_array ||= []
|
248
|
-
key_cols = key_array.map{|i| i[1] if i.class <= Sexp}.compact
|
249
|
-
val_cols = val_array.map{|i| i[1] if i.class <= Sexp}.compact
|
250
|
-
@bud_instance.scratch(name, key_cols=>val_cols)
|
251
|
-
end
|
252
|
-
|
253
287
|
def gather_collection_names(exp)
|
254
288
|
if exp[0] == :call and exp[1].nil?
|
255
289
|
@collnames << exp[2]
|
@@ -264,10 +298,6 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
264
298
|
def process_call(exp)
|
265
299
|
call, recv, op, args = exp
|
266
300
|
|
267
|
-
if op == :rename
|
268
|
-
arglist, namelit, schemahash = args
|
269
|
-
register_scratch(namelit[1], schemahash)
|
270
|
-
end
|
271
301
|
if recv and recv.class == Sexp and recv.first == :lvar and recv[1] and @iterhash[recv[1]]
|
272
302
|
if @bud_instance.respond_to?(@iterhash[recv[1]])
|
273
303
|
if @bud_instance.send(@iterhash[recv[1]]).class <= Bud::BudCollection
|
data/lib/bud/storage/dbm.rb
CHANGED
@@ -166,9 +166,9 @@ module Bud
|
|
166
166
|
public
|
167
167
|
def pending_delete(o)
|
168
168
|
if o.class <= Bud::PushElement
|
169
|
-
o.
|
169
|
+
o.wire_to(self, :delete)
|
170
170
|
elsif o.class <= Bud::BudCollection
|
171
|
-
o.pro.
|
171
|
+
o.pro.wire_to(self, :delete)
|
172
172
|
else
|
173
173
|
@to_delete = @to_delete + o.map{|t| prep_tuple(t) unless t.nil?}
|
174
174
|
end
|
data/lib/bud/viz_util.rb
CHANGED
@@ -146,9 +146,11 @@ module VizUtil #:nodoc: all
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def write_graphs(tabinf, builtin_tables, cycle, depends, rules, viz_name,
|
149
|
-
output_base, fmt, collapse, depanalysis=nil, budtime=-1,
|
149
|
+
output_base, fmt, collapse, depanalysis=nil, budtime=-1,
|
150
|
+
card_info=nil, pathsto={}, begins={})
|
150
151
|
staging = "#{viz_name}.staging"
|
151
|
-
gv = GraphGen.new(tabinf, builtin_tables, cycle, staging, budtime,
|
152
|
+
gv = GraphGen.new(tabinf, builtin_tables, cycle, staging, budtime,
|
153
|
+
collapse, card_info, pathsto, begins)
|
152
154
|
gv.process(depends)
|
153
155
|
dump(rules, output_base, gv)
|
154
156
|
gv.finish(depanalysis, fmt)
|
data/lib/bud.rb
CHANGED
@@ -62,7 +62,7 @@ $bud_instances = {} # Map from instance id => Bud instance
|
|
62
62
|
module Bud
|
63
63
|
attr_reader :budtime, :inbound, :options, :meta_parser, :viz, :rtracer, :dsock
|
64
64
|
attr_reader :tables, :builtin_tables, :channels, :zk_tables, :dbm_tables, :app_tables
|
65
|
-
attr_reader :push_sources, :push_elems, :push_joins, :scanners, :merge_targets
|
65
|
+
attr_reader :push_sources, :push_elems, :push_joins, :scanners, :merge_targets
|
66
66
|
attr_reader :this_stratum, :this_rule, :rule_orig_src, :done_bootstrap
|
67
67
|
attr_accessor :stratified_rules
|
68
68
|
attr_accessor :metrics, :periodics
|
@@ -75,7 +75,6 @@ module Bud
|
|
75
75
|
# * <tt>:port</tt> port number for this instance
|
76
76
|
# * <tt>:ext_ip</tt> IP address at which external nodes can contact this instance
|
77
77
|
# * <tt>:ext_port</tt> port number to go with <tt>:ext_ip</tt>
|
78
|
-
# * <tt>:bust_port</tt> port number for the restful HTTP messages
|
79
78
|
# * operating system interaction
|
80
79
|
# * <tt>:stdin</tt> if non-nil, reading from the +stdio+ collection results in reading from this +IO+ handle
|
81
80
|
# * <tt>:stdout</tt> writing to the +stdio+ collection results in writing to this +IO+ handle; defaults to <tt>$stdout</tt>
|
@@ -199,6 +198,11 @@ module Bud
|
|
199
198
|
toplevel? ? @budtime : toplevel.budtime
|
200
199
|
end
|
201
200
|
|
201
|
+
# Are we currently in the process of wiring together the dataflow?
|
202
|
+
def wiring?
|
203
|
+
toplevel? ? (@done_bootstrap && !@done_wiring) : toplevel.wiring?
|
204
|
+
end
|
205
|
+
|
202
206
|
private
|
203
207
|
def import_defs
|
204
208
|
@imported_defs = {} # mod name -> Module map
|
@@ -999,20 +1003,20 @@ module Bud
|
|
999
1003
|
fixpoint = false
|
1000
1004
|
first_iter = true
|
1001
1005
|
until fixpoint
|
1002
|
-
fixpoint = true
|
1003
1006
|
@scanners[stratum].each_value {|s| s.scan(first_iter)}
|
1007
|
+
fixpoint = true
|
1004
1008
|
first_iter = false
|
1005
1009
|
# flush any tuples in the pipes
|
1006
1010
|
@push_sorted_elems[stratum].each {|p| p.flush}
|
1007
1011
|
# tick deltas on any merge targets and look for more deltas
|
1008
1012
|
# check to see if any joins saw a delta
|
1009
|
-
push_joins[stratum].each do |p|
|
1013
|
+
@push_joins[stratum].each do |p|
|
1010
1014
|
if p.found_delta
|
1011
1015
|
fixpoint = false
|
1012
1016
|
p.tick_deltas
|
1013
1017
|
end
|
1014
1018
|
end
|
1015
|
-
merge_targets[stratum].each do |t|
|
1019
|
+
@merge_targets[stratum].each do |t|
|
1016
1020
|
fixpoint = false if t.tick_deltas
|
1017
1021
|
end
|
1018
1022
|
end
|
@@ -1020,7 +1024,7 @@ module Bud
|
|
1020
1024
|
@push_sorted_elems[stratum].each do |p|
|
1021
1025
|
p.stratum_end
|
1022
1026
|
end
|
1023
|
-
merge_targets[stratum].each do |t|
|
1027
|
+
@merge_targets[stratum].each do |t|
|
1024
1028
|
t.flush_deltas
|
1025
1029
|
end
|
1026
1030
|
end
|
@@ -1054,6 +1058,17 @@ module Bud
|
|
1054
1058
|
@tick_clock_time
|
1055
1059
|
end
|
1056
1060
|
|
1061
|
+
# Return the stratum number of the given collection.
|
1062
|
+
# NB: if a collection is not referenced by any rules, it is not currently
|
1063
|
+
# assigned to a strata.
|
1064
|
+
def collection_stratum(collection)
|
1065
|
+
t_stratum.each do |t|
|
1066
|
+
return t.stratum if t.predicate == collection
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
raise Bud::Error, "no such collection: #{collection}"
|
1070
|
+
end
|
1071
|
+
|
1057
1072
|
private
|
1058
1073
|
|
1059
1074
|
# Builtin Bud state (predefined collections). We could define this using the
|
@@ -1125,7 +1140,6 @@ module Bud
|
|
1125
1140
|
end
|
1126
1141
|
end
|
1127
1142
|
|
1128
|
-
private
|
1129
1143
|
######## ids and timers
|
1130
1144
|
def gen_id
|
1131
1145
|
Time.new.to_i.to_s << rand.to_s
|