bud 0.1.0.pre1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +23 -0
- data/{README → README.md} +6 -2
- data/docs/cheat.md +1 -8
- data/docs/intro.md +1 -1
- data/lib/bud/aggs.rb +16 -16
- data/lib/bud/bud_meta.rb +8 -15
- data/lib/bud/collections.rb +85 -172
- data/lib/bud/errors.rb +5 -1
- data/lib/bud/executor/elements.rb +133 -118
- data/lib/bud/executor/group.rb +6 -6
- data/lib/bud/executor/join.rb +25 -22
- data/lib/bud/metrics.rb +1 -1
- data/lib/bud/monkeypatch.rb +18 -29
- data/lib/bud/rebl.rb +5 -4
- data/lib/bud/rewrite.rb +21 -160
- data/lib/bud/source.rb +5 -5
- data/lib/bud/state.rb +13 -12
- data/lib/bud/storage/dbm.rb +13 -23
- data/lib/bud/storage/zookeeper.rb +0 -4
- data/lib/bud.rb +184 -162
- metadata +144 -216
- data/docs/deploy.md +0 -96
- data/lib/bud/deploy/countatomicdelivery.rb +0 -38
- data/lib/bud/joins.rb +0 -526
@@ -1,5 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require 'set'
|
2
2
|
require 'bud/collections'
|
3
|
+
|
3
4
|
ELEMENT_BUFSIZE = 1
|
4
5
|
|
5
6
|
module Bud
|
@@ -14,8 +15,8 @@ module Bud
|
|
14
15
|
class PushElement < BudCollection
|
15
16
|
attr_accessor :elem_name
|
16
17
|
attr_accessor :rescan, :invalidated
|
17
|
-
attr_reader :
|
18
|
-
|
18
|
+
attr_reader :inputs, :found_delta, :refcount, :wired_by, :outputs
|
19
|
+
|
19
20
|
def initialize(name_in, bud_instance, collection_name=nil, given_schema=nil, defer_schema=false, &blk)
|
20
21
|
super(name_in, bud_instance, given_schema, defer_schema)
|
21
22
|
@blk = blk
|
@@ -27,7 +28,6 @@ module Bud
|
|
27
28
|
@elem_name = name_in
|
28
29
|
@found_delta = false
|
29
30
|
@refcount = 1
|
30
|
-
@each_index = 0
|
31
31
|
@collection_name = collection_name
|
32
32
|
@invalidated = true
|
33
33
|
@rescan = true
|
@@ -42,7 +42,7 @@ module Bud
|
|
42
42
|
end
|
43
43
|
|
44
44
|
public
|
45
|
-
def print_wiring(depth=0, accum
|
45
|
+
def print_wiring(depth=0, accum="")
|
46
46
|
depth.times {print " "}
|
47
47
|
puts "#{accum} #{(self.object_id*2).to_s(16)}: #{qualified_tabname} (#{self.class})"
|
48
48
|
|
@@ -54,11 +54,11 @@ module Bud
|
|
54
54
|
next_accum = "+> "
|
55
55
|
when @deletes.object_id, @delete_keys.object_id
|
56
56
|
next_accum = "-> "
|
57
|
-
end
|
58
|
-
|
57
|
+
end
|
58
|
+
|
59
59
|
kind.each do |o|
|
60
|
-
if o.respond_to?(:print_wiring)
|
61
|
-
o.print_wiring(depth+1, next_accum)
|
60
|
+
if o.respond_to?(:print_wiring)
|
61
|
+
o.print_wiring(depth+1, next_accum)
|
62
62
|
else
|
63
63
|
(depth+1).times {print " "}
|
64
64
|
print "#{next_accum} "
|
@@ -74,16 +74,16 @@ module Bud
|
|
74
74
|
|
75
75
|
def check_wiring
|
76
76
|
if @blk.nil? and @outputs.empty? and @pendings.empty? and @deletes.empty? and @delete_keys.empty?
|
77
|
-
raise "no output specified for PushElement #{@qualified_tabname}"
|
77
|
+
raise Bud::Error, "no output specified for PushElement #{@qualified_tabname}"
|
78
78
|
end
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def set_block(&blk)
|
82
82
|
@blk = blk
|
83
83
|
end
|
84
84
|
def wire_to(element)
|
85
|
-
unless element.
|
86
|
-
raise Bud::Error, "attempt to wire_to element without insert method"
|
85
|
+
unless element.respond_to? :insert
|
86
|
+
raise Bud::Error, "attempt to wire_to element without insert method"
|
87
87
|
end
|
88
88
|
# elem_name = element.respond_to?(:tabname) ? element.tabname : element.elem_name
|
89
89
|
# puts "wiring #{self.elem_name} to #{elem_name}"
|
@@ -91,22 +91,28 @@ module Bud
|
|
91
91
|
element.wired_by << self if element.respond_to? :wired_by
|
92
92
|
end
|
93
93
|
def wire_to_pending(element)
|
94
|
-
|
95
|
-
|
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
|
96
98
|
# puts "wiring #{self.elem_name} to #{elem_name}(pending)"
|
97
99
|
@pendings << element
|
98
100
|
element.wired_by << self if element.respond_to? :wired_by
|
99
101
|
end
|
100
102
|
def wire_to_delete(element)
|
101
|
-
|
102
|
-
|
103
|
+
unless element.respond_to? :pending_delete
|
104
|
+
raise Bud::Error, "attempt to wire_to_delete element without pending_delete method"
|
105
|
+
end
|
106
|
+
# elem_name = element.respond_to?(:tabname) ? element.tabname : element.elem_name
|
103
107
|
# puts "wiring #{self.elem_name} to #{elem_name}(delete)"
|
104
108
|
@deletes << element
|
105
109
|
element.wired_by << self if element.respond_to? :wired_by
|
106
110
|
end
|
107
111
|
def wire_to_delete_by_key(element)
|
108
|
-
|
109
|
-
|
112
|
+
unless element.respond_to? :pending_delete_keys
|
113
|
+
raise Bud::Error, "attempt to wire_to_delete_by_key element without pending_delete_keys method"
|
114
|
+
end
|
115
|
+
# elem_name = element.respond_to?(:tabname) ? element.tabname : element.elem_name
|
110
116
|
# puts "wiring #{self.elem_name} to #{elem_name}(delete)"
|
111
117
|
@delete_keys << element
|
112
118
|
element.wired_by << self if element.respond_to? :wired_by
|
@@ -116,7 +122,6 @@ module Bud
|
|
116
122
|
false
|
117
123
|
end
|
118
124
|
|
119
|
-
|
120
125
|
def insert(item, source=nil)
|
121
126
|
push_out(item)
|
122
127
|
end
|
@@ -131,36 +136,34 @@ module Bud
|
|
131
136
|
|
132
137
|
def push_out(item, do_block=true)
|
133
138
|
if item
|
134
|
-
|
135
|
-
|
136
|
-
item =
|
137
|
-
begin
|
138
|
-
item = blk.call item
|
139
|
-
rescue Exception
|
140
|
-
raise
|
141
|
-
end
|
139
|
+
if do_block && @blk
|
140
|
+
item = item.to_a if @blk.arity > 1
|
141
|
+
item = @blk.call item
|
142
142
|
end
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
143
|
+
|
144
|
+
unless item.nil?
|
145
|
+
@outputs.each do |ou|
|
146
|
+
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
|
+
ou.insert(item, self)
|
150
|
+
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
|
+
ou.do_insert(item, ou.new_delta)
|
154
|
+
else
|
155
|
+
raise Bud::Error, "expected either a PushElement or a BudCollection"
|
156
|
+
end
|
154
157
|
end
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
158
|
+
|
159
|
+
# for all the following, o is a BudCollection
|
160
|
+
@deletes.each{|o| o.pending_delete([item])}
|
161
|
+
@delete_keys.each{|o| o.pending_delete_keys([item])}
|
162
|
+
@pendings.each{|o| o.pending_merge([item])}
|
163
|
+
end
|
160
164
|
end
|
161
165
|
end
|
162
166
|
|
163
|
-
|
164
167
|
# default for stateless elements
|
165
168
|
public
|
166
169
|
def add_rescan_invalidate(rescan, invalidate)
|
@@ -170,23 +173,25 @@ module Bud
|
|
170
173
|
rescan << self
|
171
174
|
end
|
172
175
|
|
173
|
-
# pass the current state to the non-element outputs, and see if they end
|
176
|
+
# pass the current state to the non-element outputs, and see if they end
|
177
|
+
# up marking this node for rescan
|
174
178
|
invalidate_tables(rescan, invalidate)
|
175
179
|
|
176
|
-
# finally, if this node is in rescan, pass the request on to all source
|
180
|
+
# finally, if this node is in rescan, pass the request on to all source
|
181
|
+
# elements
|
177
182
|
if rescan.member? self
|
178
|
-
|
183
|
+
rescan += srcs
|
179
184
|
end
|
180
185
|
end
|
181
186
|
|
182
187
|
def invalidate_tables(rescan, invalidate)
|
183
|
-
# exchange rescan and invalidate information with tables. If this node is
|
184
|
-
# table (if it is a scratch). And if
|
188
|
+
# exchange rescan and invalidate information with tables. If this node is
|
189
|
+
# in rescan, it may invalidate a target table (if it is a scratch). And if
|
190
|
+
# the target node is invalidated, this node marks itself for rescan to
|
185
191
|
# enable a refill of that table at run-time
|
186
|
-
|
187
192
|
@outputs.each do |o|
|
188
193
|
unless o.class <= PushElement
|
189
|
-
o.add_rescan_invalidate(rescan, invalidate)
|
194
|
+
o.add_rescan_invalidate(rescan, invalidate)
|
190
195
|
rescan << self if invalidate.member? o
|
191
196
|
end
|
192
197
|
end
|
@@ -211,45 +216,48 @@ module Bud
|
|
211
216
|
# setup_accessors
|
212
217
|
#end
|
213
218
|
|
214
|
-
|
219
|
+
|
215
220
|
####
|
216
221
|
# and now, the Bloom-facing methods
|
217
222
|
public
|
218
|
-
def pro(the_name
|
223
|
+
def pro(the_name=@elem_name, the_schema=schema, &blk)
|
219
224
|
toplevel = @bud_instance.toplevel
|
220
|
-
elem = Bud::PushElement.new('project' + object_id.to_s,
|
221
|
-
|
225
|
+
elem = Bud::PushElement.new('project' + object_id.to_s,
|
226
|
+
toplevel.this_rule_context,
|
227
|
+
@collection_name, the_schema)
|
222
228
|
self.wire_to(elem)
|
223
229
|
elem.set_block(&blk)
|
224
|
-
toplevel.push_elems[[self.object_id
|
230
|
+
toplevel.push_elems[[self.object_id, :pro, blk]] = elem
|
225
231
|
return elem
|
226
232
|
end
|
227
|
-
|
233
|
+
|
228
234
|
alias each pro
|
229
|
-
|
235
|
+
|
230
236
|
public
|
231
|
-
def each_with_index(the_name
|
237
|
+
def each_with_index(the_name=elem_name, the_schema=schema, &blk)
|
232
238
|
toplevel = @bud_instance.toplevel
|
233
|
-
elem = Bud::PushEachWithIndex.new('each_with_index' + object_id.to_s,
|
239
|
+
elem = Bud::PushEachWithIndex.new('each_with_index' + object_id.to_s,
|
240
|
+
toplevel.this_rule_context,
|
241
|
+
@collection_name)
|
234
242
|
elem.set_block(&blk)
|
235
243
|
self.wire_to(elem)
|
236
|
-
toplevel.push_elems[[self.object_id
|
244
|
+
toplevel.push_elems[[self.object_id, :each, blk]] = elem
|
237
245
|
end
|
238
|
-
|
246
|
+
|
239
247
|
def join(elem2, &blk)
|
240
248
|
# cached = @bud_instance.push_elems[[self.object_id,:join,[self,elem2], @bud_instance, blk]]
|
241
249
|
# if cached.nil?
|
242
250
|
elem2 = elem2.to_push_elem unless elem2.class <= PushElement
|
243
251
|
toplevel = @bud_instance.toplevel
|
244
|
-
join = Bud::PushSHJoin.new([self,elem2], toplevel.this_rule_context, [])
|
252
|
+
join = Bud::PushSHJoin.new([self, elem2], toplevel.this_rule_context, [])
|
245
253
|
self.wire_to(join)
|
246
254
|
elem2.wire_to(join)
|
247
|
-
toplevel.push_elems[[self.object_id
|
255
|
+
toplevel.push_elems[[self.object_id, :join, [self, elem2], toplevel, blk]] = join
|
248
256
|
toplevel.push_joins[toplevel.this_stratum] << join
|
249
257
|
# else
|
250
258
|
# cached.refcount += 1
|
251
259
|
# end
|
252
|
-
return toplevel.push_elems[[self.object_id
|
260
|
+
return toplevel.push_elems[[self.object_id, :join, [self, elem2], toplevel, blk]]
|
253
261
|
end
|
254
262
|
def *(elem2, &blk)
|
255
263
|
join(elem2, &blk)
|
@@ -260,7 +268,7 @@ module Bud
|
|
260
268
|
notin_elem = Bud::PushNotIn.new([self, elem2], toplevel.this_rule_context, preds, &blk)
|
261
269
|
self.wire_to(notin_elem)
|
262
270
|
elem2.wire_to(notin_elem)
|
263
|
-
toplevel.push_elems[[self.object_id, :notin, collection, toplevel, blk]]
|
271
|
+
toplevel.push_elems[[self.object_id, :notin, collection, toplevel, blk]] = notin_elem
|
264
272
|
return notin_elem
|
265
273
|
end
|
266
274
|
|
@@ -268,20 +276,20 @@ module Bud
|
|
268
276
|
if source.class <= PushElement and wiring?
|
269
277
|
source.wire_to(self)
|
270
278
|
else
|
271
|
-
source.each{|i| self << i}
|
279
|
+
source.each {|i| self << i}
|
272
280
|
end
|
273
281
|
end
|
274
282
|
alias <= merge
|
275
283
|
superator "<~" do |o|
|
276
|
-
raise Bud::Error, "
|
284
|
+
raise Bud::Error, "illegal use of <~ with pusher '#{tabname}' on left"
|
277
285
|
end
|
278
286
|
|
279
287
|
superator "<-" do |o|
|
280
|
-
raise Bud::Error, "
|
288
|
+
raise Bud::Error, "illegal use of <- with pusher '#{tabname}' on left"
|
281
289
|
end
|
282
290
|
|
283
291
|
superator "<+" do |o|
|
284
|
-
raise Bud::Error, "
|
292
|
+
raise Bud::Error, "illegal use of <+ with pusher '#{tabname}' on left"
|
285
293
|
end
|
286
294
|
|
287
295
|
def group(keycols, *aggpairs, &blk)
|
@@ -293,13 +301,13 @@ module Bud
|
|
293
301
|
aggcols = []
|
294
302
|
aggcolsdups.each_with_index do |n, i|
|
295
303
|
aggcols << "#{n.downcase}_#{i}".to_sym
|
296
|
-
end
|
304
|
+
end
|
297
305
|
if aggcols.empty?
|
298
306
|
the_schema = keynames
|
299
307
|
else
|
300
308
|
the_schema = { keynames => aggcols }
|
301
309
|
end
|
302
|
-
|
310
|
+
|
303
311
|
aggpairs = aggpairs.map{|ap| ap[1].nil? ? [ap[0]] : [ap[0], canonicalize_col(ap[1])]}
|
304
312
|
toplevel = @bud_instance.toplevel
|
305
313
|
# if @bud_instance.push_elems[[self.object_id, :group, keycols, aggpairs, blk]].nil?
|
@@ -325,7 +333,7 @@ module Bud
|
|
325
333
|
k[2]
|
326
334
|
end
|
327
335
|
end
|
328
|
-
aggpairs = [[agg,collection]]
|
336
|
+
aggpairs = [[agg, collection]]
|
329
337
|
# if toplevel.push_elems[[self.object_id,:argagg, gbkey_cols, aggpairs, blk]].nil?
|
330
338
|
aa = Bud::PushArgAgg.new('argagg'+Time.new.tv_usec.to_s, toplevel.this_rule_context, @collection_name, gbkey_cols, aggpairs, schema, &blk)
|
331
339
|
self.wire_to(aa)
|
@@ -345,8 +353,10 @@ module Bud
|
|
345
353
|
wire_to(elem)
|
346
354
|
elem
|
347
355
|
end
|
348
|
-
def push_predicate(pred_symbol, name=nil, bud_instance=nil,
|
349
|
-
|
356
|
+
def push_predicate(pred_symbol, name=nil, bud_instance=nil,
|
357
|
+
the_schema=nil, &blk)
|
358
|
+
elem = Bud::PushPredicate.new(pred_symbol, name, bud_instance,
|
359
|
+
the_schema, &blk)
|
350
360
|
wire_to(elem)
|
351
361
|
elem
|
352
362
|
end
|
@@ -368,44 +378,45 @@ module Bud
|
|
368
378
|
def one?(name=nil, bud_instance=nil, the_schema=nil, &blk)
|
369
379
|
push_predicate(:one?, name, bud_instance, the_schema, &blk)
|
370
380
|
end
|
371
|
-
|
381
|
+
|
372
382
|
def reduce(initial, &blk)
|
373
383
|
@memo = initial
|
374
|
-
retval = Bud::PushReduce.new(
|
384
|
+
retval = Bud::PushReduce.new("reduce#{Time.new.tv_usec}",
|
385
|
+
@bud_instance, @collection_name,
|
386
|
+
schema, initial, &blk)
|
375
387
|
self.wire_to(retval)
|
376
388
|
retval
|
377
389
|
end
|
378
|
-
|
390
|
+
|
379
391
|
alias on_exists? pro
|
380
392
|
def on_include?(item, &blk)
|
381
393
|
toplevel = @bud_instance.toplevel
|
382
|
-
if toplevel.push_elems[[self.object_id
|
394
|
+
if toplevel.push_elems[[self.object_id, :on_include?, item, blk]].nil?
|
383
395
|
inc = pro{|i| blk.call(item) if i == item and not blk.nil?}
|
384
396
|
wire_to(inc)
|
385
|
-
toplevel.push_elems[[self.object_id
|
397
|
+
toplevel.push_elems[[self.object_id, :on_include?, item, blk]] = inc
|
386
398
|
end
|
387
|
-
toplevel.push_elems[[self.object_id
|
399
|
+
toplevel.push_elems[[self.object_id, :on_include?, item, blk]]
|
388
400
|
end
|
389
401
|
def inspected
|
390
402
|
toplevel = @bud_instance.toplevel
|
391
|
-
if toplevel.push_elems[[self.object_id
|
403
|
+
if toplevel.push_elems[[self.object_id, :inspected]].nil?
|
392
404
|
ins = pro{|i| [i.inspect]}
|
393
405
|
self.wire_to(ins)
|
394
|
-
toplevel.push_elems[[self.object_id
|
406
|
+
toplevel.push_elems[[self.object_id, :inspected]] = ins
|
395
407
|
end
|
396
|
-
toplevel.push_elems[[self.object_id
|
408
|
+
toplevel.push_elems[[self.object_id, :inspected]]
|
397
409
|
end
|
398
|
-
|
410
|
+
|
399
411
|
def to_enum
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
412
|
+
# scr = @bud_instance.scratch(("scratch_" + Process.pid.to_s + "_" + object_id.to_s + "_" + rand(10000).to_s).to_sym, schema)
|
413
|
+
scr = []
|
414
|
+
self.wire_to(scr)
|
415
|
+
scr
|
404
416
|
end
|
405
|
-
end
|
417
|
+
end
|
406
418
|
|
407
419
|
class PushStatefulElement < PushElement
|
408
|
-
|
409
420
|
def rescan_at_tick
|
410
421
|
true
|
411
422
|
end
|
@@ -415,10 +426,9 @@ module Bud
|
|
415
426
|
end
|
416
427
|
|
417
428
|
def add_rescan_invalidate(rescan, invalidate)
|
418
|
-
# If an upstream node is set to rescan, a stateful node invalidates its
|
419
|
-
# In addition, a stateful node always rescans its own contents
|
420
|
-
# its source nodes
|
421
|
-
|
429
|
+
# If an upstream node is set to rescan, a stateful node invalidates its
|
430
|
+
# cache. In addition, a stateful node always rescans its own contents
|
431
|
+
# (doesn't need to pass a rescan request to its its source nodes).
|
422
432
|
rescan << self
|
423
433
|
srcs = non_temporal_predecessors
|
424
434
|
if srcs.any? {|p| rescan.member? p}
|
@@ -435,7 +445,7 @@ module Bud
|
|
435
445
|
@in_buf = []
|
436
446
|
super(elem_name, bud_instance, collection_name, schema_in, &blk)
|
437
447
|
end
|
438
|
-
|
448
|
+
|
439
449
|
def insert(item, source)
|
440
450
|
@in_buf << item
|
441
451
|
end
|
@@ -450,13 +460,14 @@ module Bud
|
|
450
460
|
@in_buf.clear
|
451
461
|
end
|
452
462
|
end
|
453
|
-
|
463
|
+
|
454
464
|
class PushSort < PushStatefulElement
|
455
|
-
def initialize(elem_name=nil, bud_instance=nil, collection_name=nil,
|
465
|
+
def initialize(elem_name=nil, bud_instance=nil, collection_name=nil,
|
466
|
+
schema_in=nil, &blk)
|
456
467
|
@sortbuf = []
|
457
468
|
super(elem_name, bud_instance, collection_name, schema_in, &blk)
|
458
469
|
end
|
459
|
-
|
470
|
+
|
460
471
|
def insert(item, source)
|
461
472
|
@sortbuf << item
|
462
473
|
end
|
@@ -476,12 +487,13 @@ module Bud
|
|
476
487
|
@sortbuf = []
|
477
488
|
end
|
478
489
|
end
|
479
|
-
|
490
|
+
|
480
491
|
class ScannerElement < PushElement
|
481
492
|
attr_reader :collection
|
482
493
|
attr_reader :rescan_set, :invalidate_set
|
483
|
-
|
484
|
-
|
494
|
+
|
495
|
+
def initialize(elem_name, bud_instance, collection_in,
|
496
|
+
the_schema=collection_in.schema, &blk)
|
485
497
|
super(elem_name, bud_instance, collection_in.qualified_tabname, the_schema)
|
486
498
|
@collection = collection_in
|
487
499
|
@rescan_set = []
|
@@ -496,8 +508,9 @@ module Bud
|
|
496
508
|
@collection.invalidate_at_tick # need to scan afresh if collection invalidated.
|
497
509
|
end
|
498
510
|
|
511
|
+
# collection of others to rescan/invalidate if this scanner's collection
|
512
|
+
# were to be invalidated.
|
499
513
|
def invalidate_at_tick(rescan, invalidate)
|
500
|
-
# collection of others to rescan/invalidate if this scanner's collection were to be invalidated.
|
501
514
|
@rescan_set = rescan
|
502
515
|
@invalidate_set = invalidate
|
503
516
|
end
|
@@ -507,19 +520,19 @@ module Bud
|
|
507
520
|
# scanner elements are never directly connected to tables.
|
508
521
|
rescan << self if invalidate.member? @collection
|
509
522
|
|
510
|
-
# Note also that this node can be nominated for rescan by a target node;
|
511
|
-
# can be set to rescan even if the
|
523
|
+
# Note also that this node can be nominated for rescan by a target node;
|
524
|
+
# in other words, a scanner element can be set to rescan even if the
|
525
|
+
# collection is not invalidated.
|
512
526
|
end
|
513
527
|
|
514
528
|
def scan(first_iter)
|
515
|
-
if
|
529
|
+
if first_iter
|
516
530
|
if rescan
|
517
|
-
#
|
518
|
-
@collection.each_raw {|item|
|
519
|
-
push_out(item)
|
520
|
-
}
|
531
|
+
# Scan entire storage
|
532
|
+
@collection.each_raw {|item| push_out(item)}
|
521
533
|
else
|
522
|
-
# In the first iteration, tick_delta would be non-null IFF the
|
534
|
+
# In the first iteration, tick_delta would be non-null IFF the
|
535
|
+
# collection has grown in an earlier stratum
|
523
536
|
@collection.tick_delta.each {|item| push_out(item)}
|
524
537
|
end
|
525
538
|
end
|
@@ -530,14 +543,15 @@ module Bud
|
|
530
543
|
end
|
531
544
|
|
532
545
|
class PushReduce < PushStatefulElement
|
533
|
-
def initialize(elem_name, bud_instance, collection_name,
|
546
|
+
def initialize(elem_name, bud_instance, collection_name,
|
547
|
+
schema_in, initial, &blk)
|
534
548
|
@memo = initial
|
535
549
|
@blk = blk
|
536
550
|
super(elem_name, bud_instance, collection_name, schema)
|
537
551
|
end
|
538
552
|
|
539
553
|
def insert(i, source=nil)
|
540
|
-
@memo = @blk.call(@memo,i)
|
554
|
+
@memo = @blk.call(@memo, i)
|
541
555
|
end
|
542
556
|
|
543
557
|
def invalidate_cache
|
@@ -567,11 +581,12 @@ module Bud
|
|
567
581
|
|
568
582
|
invalidate_tables(rescan, invalidate)
|
569
583
|
|
570
|
-
# This node has some state (@each_index), but not the tuples. If it is in
|
571
|
-
# sources to rescan, and restart its
|
584
|
+
# This node has some state (@each_index), but not the tuples. If it is in
|
585
|
+
# rescan mode, then it must ask its sources to rescan, and restart its
|
586
|
+
# index.
|
572
587
|
if rescan.member? self
|
573
588
|
invalidate << self
|
574
|
-
|
589
|
+
rescan += srcs
|
575
590
|
end
|
576
591
|
end
|
577
592
|
|
@@ -585,7 +600,7 @@ module Bud
|
|
585
600
|
|
586
601
|
def insert(item, source=nil)
|
587
602
|
ix = @each_index
|
588
|
-
@each_index
|
603
|
+
@each_index += 1
|
589
604
|
push_out([item, ix])
|
590
605
|
end
|
591
606
|
end
|
data/lib/bud/executor/group.rb
CHANGED
@@ -5,7 +5,7 @@ module Bud
|
|
5
5
|
def initialize(elem_name, bud_instance, collection_name, keys_in, aggpairs_in, schema_in, &blk)
|
6
6
|
@groups = {}
|
7
7
|
if keys_in.nil?
|
8
|
-
@keys = []
|
8
|
+
@keys = []
|
9
9
|
else
|
10
10
|
@keys = keys_in.map{|k| k[1]}
|
11
11
|
end
|
@@ -13,9 +13,9 @@ module Bud
|
|
13
13
|
@aggpairs = aggpairs_in.map{|ap| ap[1].nil? ? [ap[0]] : [ap[0], ap[1][1]]}
|
14
14
|
super(elem_name, bud_instance, collection_name, schema_in, &blk)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def insert(item, source)
|
18
|
-
key = @keys.map{|k| item[k]}
|
18
|
+
key = @keys.map{|k| item[k]}
|
19
19
|
@aggpairs.each_with_index do |ap, agg_ix|
|
20
20
|
agg_input = ap[1].nil? ? item : item[ap[1]]
|
21
21
|
agg = (@groups[key].nil? or @groups[key][agg_ix].nil?) ? ap[0].send(:init, agg_input) : ap[0].send(:trans, @groups[key][agg_ix], agg_input)[0]
|
@@ -43,7 +43,7 @@ module Bud
|
|
43
43
|
#@groups = {}
|
44
44
|
end
|
45
45
|
end
|
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
49
|
raise "Multiple aggpairs #{aggpairs_in.map{|a| a.class.name}} in ArgAgg; only one allowed" if aggpairs_in.length > 1
|
@@ -63,7 +63,7 @@ module Bud
|
|
63
63
|
def insert(item, source)
|
64
64
|
key = @keys.map{|k| item[k]}
|
65
65
|
@aggpairs.each_with_index do |ap, agg_ix|
|
66
|
-
|
66
|
+
agg_input = item[ap[1]]
|
67
67
|
if @groups[key].nil?
|
68
68
|
agg = ap[0].send(:init, agg_input)
|
69
69
|
@winners[key] = [item]
|
@@ -88,7 +88,7 @@ module Bud
|
|
88
88
|
@groups[key] ||= Array.new(@aggpairs.length)
|
89
89
|
@groups[key][agg_ix] = agg
|
90
90
|
#push_out(nil)
|
91
|
-
end
|
91
|
+
end
|
92
92
|
end
|
93
93
|
|
94
94
|
def flush
|