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
data/lib/bud/collections.rb
CHANGED
@@ -17,7 +17,7 @@ module Bud
|
|
17
17
|
class BudCollection
|
18
18
|
include Enumerable
|
19
19
|
|
20
|
-
attr_accessor :bud_instance, :
|
20
|
+
attr_accessor :bud_instance, :tabname # :nodoc: all
|
21
21
|
attr_reader :cols, :key_cols # :nodoc: all
|
22
22
|
attr_reader :struct
|
23
23
|
attr_reader :storage, :delta, :new_delta, :pending, :tick_delta # :nodoc: all
|
@@ -25,6 +25,7 @@ module Bud
|
|
25
25
|
attr_accessor :invalidated, :to_delete, :rescan
|
26
26
|
attr_accessor :is_source
|
27
27
|
attr_accessor :wired_by
|
28
|
+
attr_accessor :accumulate_tick_deltas # updated in bud.do_wiring
|
28
29
|
|
29
30
|
def initialize(name, bud_instance, given_schema=nil, defer_schema=false) # :nodoc: all
|
30
31
|
@tabname = name
|
@@ -32,6 +33,7 @@ module Bud
|
|
32
33
|
@invalidated = true
|
33
34
|
@is_source = true # unless it shows up on the lhs of some rule
|
34
35
|
@wired_by = []
|
36
|
+
@accumulate_tick_deltas = false
|
35
37
|
init_schema(given_schema) unless given_schema.nil? and defer_schema
|
36
38
|
init_buffers
|
37
39
|
end
|
@@ -46,8 +48,6 @@ module Bud
|
|
46
48
|
public
|
47
49
|
def init_schema(given_schema)
|
48
50
|
given_schema ||= {[:key]=>[:val]}
|
49
|
-
|
50
|
-
|
51
51
|
@given_schema = given_schema
|
52
52
|
@cols, @key_cols = BudCollection.parse_schema(given_schema)
|
53
53
|
# Check that no location specifiers appear in the schema. In the case of
|
@@ -91,7 +91,7 @@ module Bud
|
|
91
91
|
cols = key_cols + val_cols
|
92
92
|
cols.each do |c|
|
93
93
|
if c.class != Symbol
|
94
|
-
raise Bud::Error, "
|
94
|
+
raise Bud::Error, "invalid column name \"#{c}\", type \"#{c.class}\""
|
95
95
|
end
|
96
96
|
end
|
97
97
|
if cols.uniq.length < cols.length
|
@@ -105,11 +105,6 @@ module Bud
|
|
105
105
|
"#{self.class}:#{self.object_id.to_s(16)} [#{qualified_tabname}]"
|
106
106
|
end
|
107
107
|
|
108
|
-
public
|
109
|
-
def clone_empty #:nodoc: all
|
110
|
-
self.class.new(tabname, bud_instance, @given_schema)
|
111
|
-
end
|
112
|
-
|
113
108
|
# produces the schema in a format that is useful as the schema specification for another table
|
114
109
|
public
|
115
110
|
def schema
|
@@ -140,24 +135,14 @@ module Bud
|
|
140
135
|
# set up schema accessors, which are class methods
|
141
136
|
@cols_access = Module.new do
|
142
137
|
sc.each_with_index do |c, i|
|
143
|
-
|
138
|
+
define_method c do
|
144
139
|
[@tabname, i, c]
|
145
140
|
end
|
146
141
|
end
|
147
142
|
end
|
148
143
|
self.extend @cols_access
|
149
|
-
|
150
|
-
# now set up a Module for tuple accessors, which are instance methods
|
151
|
-
@tupaccess = Module.new do
|
152
|
-
sc.each_with_index do |colname, offset|
|
153
|
-
define_method colname do
|
154
|
-
self[offset]
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
144
|
end
|
159
145
|
|
160
|
-
|
161
146
|
private
|
162
147
|
def name_reserved?(colname)
|
163
148
|
reserved = eval "defined?(#{colname})"
|
@@ -174,12 +159,6 @@ module Bud
|
|
174
159
|
return true
|
175
160
|
end
|
176
161
|
|
177
|
-
# define methods to access tuple attributes by column name
|
178
|
-
public
|
179
|
-
def tuple_accessors(tup)
|
180
|
-
tup # XXX remove tuple_acessors everywhere.
|
181
|
-
end
|
182
|
-
|
183
162
|
# generate a tuple with the schema of this collection and nil values in each attribute
|
184
163
|
public
|
185
164
|
def null_tuple
|
@@ -208,7 +187,7 @@ module Bud
|
|
208
187
|
|
209
188
|
# projection
|
210
189
|
public
|
211
|
-
def pro(the_name
|
190
|
+
def pro(the_name=tabname, the_schema=schema, &blk)
|
212
191
|
pusher = to_push_elem(the_name, the_schema)
|
213
192
|
pusher_pro = pusher.pro(&blk)
|
214
193
|
pusher_pro.elem_name = the_name
|
@@ -217,45 +196,46 @@ module Bud
|
|
217
196
|
end
|
218
197
|
|
219
198
|
public
|
220
|
-
def each_with_index(the_name
|
199
|
+
def each_with_index(the_name=tabname, the_schema=schema, &blk)
|
221
200
|
toplevel = @bud_instance.toplevel
|
222
201
|
if not toplevel.done_wiring
|
223
202
|
proj = pro(the_name, the_schema)
|
224
|
-
elem = Bud::PushEachWithIndex.new('each_with_index' + object_id.to_s,
|
203
|
+
elem = Bud::PushEachWithIndex.new('each_with_index' + object_id.to_s,
|
204
|
+
toplevel.this_rule_context, tabname)
|
225
205
|
elem.set_block(&blk)
|
226
206
|
proj.wire_to(elem)
|
227
|
-
toplevel.push_elems[[self.object_id
|
207
|
+
toplevel.push_elems[[self.object_id, :each, blk]] = elem
|
228
208
|
elem
|
229
209
|
else
|
230
210
|
storage.each_with_index
|
231
211
|
end
|
232
212
|
end
|
233
213
|
|
234
|
-
|
235
|
-
#
|
236
|
-
#
|
237
|
-
#
|
214
|
+
# ruby 1.9 defines flat_map to return "a new array with the concatenated
|
215
|
+
# results of running <em>block</em> once for every element". So we wire the
|
216
|
+
# input to a pro(&blk), and wire the output of that pro to a group that does
|
217
|
+
# accum.
|
238
218
|
public
|
239
219
|
def flat_map(&blk)
|
240
220
|
pusher = self.pro(&blk)
|
241
221
|
toplevel = @bud_instance.toplevel
|
242
222
|
elem = Bud::PushElement.new(tabname, toplevel.this_rule_context, tabname)
|
243
223
|
pusher.wire_to(elem)
|
244
|
-
f = Proc.new do |t|
|
245
|
-
t.each do |i|
|
246
|
-
elem.push_out(i,false)
|
224
|
+
f = Proc.new do |t|
|
225
|
+
t.each do |i|
|
226
|
+
elem.push_out(i, false)
|
247
227
|
end
|
248
228
|
nil
|
249
229
|
end
|
250
230
|
elem.set_block(&f)
|
251
|
-
toplevel.push_elems[[self.object_id
|
231
|
+
toplevel.push_elems[[self.object_id, :flatten]] = elem
|
252
232
|
return elem
|
253
233
|
end
|
254
234
|
|
255
|
-
public
|
235
|
+
public
|
256
236
|
def sort(&blk)
|
257
237
|
pusher = self.pro
|
258
|
-
pusher.sort(
|
238
|
+
pusher.sort("sort#{object_id}", @bud_instance, @cols, &blk)
|
259
239
|
end
|
260
240
|
|
261
241
|
def rename(the_name, the_schema=nil)
|
@@ -300,7 +280,6 @@ module Bud
|
|
300
280
|
rule_num = bud_instance.this_rule
|
301
281
|
addr = nil
|
302
282
|
addr = bud_instance.ip_port unless bud_instance.port.nil?
|
303
|
-
rule_txt = nil
|
304
283
|
bud_instance.metrics[:collections] ||= {}
|
305
284
|
bud_instance.metrics[:collections][{:addr=>addr, :tabname=>qualified_tabname, :strat_num=>strat_num, :rule_num=>rule_num}] ||= 0
|
306
285
|
bud_instance.metrics[:collections][{:addr=>addr, :tabname=>qualified_tabname, :strat_num=>strat_num, :rule_num=>rule_num}] += 1
|
@@ -311,7 +290,7 @@ module Bud
|
|
311
290
|
bufs.each do |b|
|
312
291
|
b.each_value do |v|
|
313
292
|
tick_metrics if bud_instance and bud_instance.options[:metrics]
|
314
|
-
yield
|
293
|
+
yield v
|
315
294
|
end
|
316
295
|
end
|
317
296
|
end
|
@@ -365,7 +344,7 @@ module Bud
|
|
365
344
|
# is this enforced in do_insert?
|
366
345
|
check_enumerable(k)
|
367
346
|
t = @storage[k]
|
368
|
-
return t.nil? ? @delta[k] :
|
347
|
+
return t.nil? ? @delta[k] : t
|
369
348
|
end
|
370
349
|
|
371
350
|
# checks for +item+ in the collection
|
@@ -400,7 +379,7 @@ module Bud
|
|
400
379
|
private
|
401
380
|
def raise_pk_error(new_guy, old)
|
402
381
|
key = get_key_vals(old)
|
403
|
-
raise KeyConstraintError, "key conflict inserting #{new_guy.inspect} into \"#{tabname}\": existing tuple #{old.inspect}, key = #{key.inspect}"
|
382
|
+
raise Bud::KeyConstraintError, "key conflict inserting #{new_guy.inspect} into \"#{tabname}\": existing tuple #{old.inspect}, key = #{key.inspect}"
|
404
383
|
end
|
405
384
|
|
406
385
|
private
|
@@ -408,24 +387,22 @@ module Bud
|
|
408
387
|
return o if o.class == @struct
|
409
388
|
if o.class == Array
|
410
389
|
if @struct.nil?
|
411
|
-
sch =
|
390
|
+
sch = (1 .. o.length).map{|i| "c#{i}".to_sym}
|
412
391
|
init_schema(sch)
|
413
392
|
end
|
414
|
-
o = o.take(@structlen) if o.length > @structlen
|
415
393
|
elsif o.kind_of? Struct
|
416
394
|
init_schema(o.members.map{|m| m.to_sym}) if @struct.nil?
|
417
|
-
o = o.take(@structlen)
|
418
395
|
else
|
419
|
-
raise TypeError, "
|
396
|
+
raise Bud::TypeError, "array or struct type expected in \"#{qualified_tabname}\": #{o.inspect}"
|
420
397
|
end
|
398
|
+
|
399
|
+
o = o.take(@structlen) if o.length > @structlen
|
421
400
|
return @struct.new(*o)
|
422
401
|
end
|
423
402
|
|
424
403
|
private
|
425
404
|
def get_key_vals(t)
|
426
|
-
@key_colnums.map
|
427
|
-
t[i]
|
428
|
-
end
|
405
|
+
@key_colnums.map {|i| t[i]}
|
429
406
|
end
|
430
407
|
|
431
408
|
public
|
@@ -445,7 +422,7 @@ module Bud
|
|
445
422
|
|
446
423
|
old = store[key]
|
447
424
|
if old.nil?
|
448
|
-
store[key] =
|
425
|
+
store[key] = o
|
449
426
|
else
|
450
427
|
raise_pk_error(o, old) unless old == o
|
451
428
|
end
|
@@ -465,7 +442,7 @@ module Bud
|
|
465
442
|
private
|
466
443
|
def check_enumerable(o)
|
467
444
|
unless o.nil? or o.class < Enumerable or o.class <= Proc
|
468
|
-
raise TypeError, "
|
445
|
+
raise Bud::TypeError, "collection #{qualified_tabname} expected Enumerable value, not #{o.inspect} (class = #{o.class})"
|
469
446
|
end
|
470
447
|
end
|
471
448
|
|
@@ -502,34 +479,27 @@ module Bud
|
|
502
479
|
init_schema((0..arity-1).map{|indx| ("c"+indx.to_s).to_sym})
|
503
480
|
end
|
504
481
|
|
505
|
-
|
506
|
-
def
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
next if old.nil?
|
511
|
-
if old != t
|
512
|
-
raise_pk_error(t, old)
|
513
|
-
else
|
514
|
-
return true
|
515
|
-
end
|
482
|
+
protected
|
483
|
+
def add_merge_target
|
484
|
+
toplevel = @bud_instance.toplevel
|
485
|
+
if toplevel.done_bootstrap
|
486
|
+
toplevel.merge_targets[toplevel.this_stratum] << self
|
516
487
|
end
|
517
|
-
return false
|
518
488
|
end
|
519
489
|
|
520
490
|
public
|
521
491
|
def merge(o, buf=@delta) # :nodoc: all
|
522
492
|
toplevel = @bud_instance.toplevel
|
523
493
|
if o.class <= Bud::PushElement
|
524
|
-
|
494
|
+
add_merge_target
|
525
495
|
deduce_schema(o) if @cols.nil?
|
526
496
|
o.wire_to self
|
527
497
|
elsif o.class <= Bud::BudCollection
|
528
|
-
|
498
|
+
add_merge_target
|
529
499
|
deduce_schema(o) if @cols.nil?
|
530
500
|
o.pro.wire_to self
|
531
501
|
elsif o.class <= Proc and toplevel.done_bootstrap and not toplevel.done_wiring and not o.nil?
|
532
|
-
|
502
|
+
add_merge_target
|
533
503
|
tbl = register_coll_expr(o)
|
534
504
|
tbl.pro.wire_to self
|
535
505
|
else
|
@@ -543,17 +513,9 @@ module Bud
|
|
543
513
|
return self
|
544
514
|
end
|
545
515
|
|
546
|
-
# def prep_coll_expr(o)
|
547
|
-
# o = o.uniq.compact if o.respond_to?(:uniq)
|
548
|
-
# check_enumerable(o)
|
549
|
-
# establish_schema(o) if @cols.nil?
|
550
|
-
# o
|
551
|
-
# end
|
552
|
-
|
553
516
|
def register_coll_expr(expr)
|
554
|
-
|
555
|
-
|
556
|
-
cols = (1..@cols.length).map{|i| ("c"+i.to_s).to_sym} unless @cols.nil?
|
517
|
+
coll_name = "expr_#{expr.object_id}"
|
518
|
+
cols = (1..@cols.length).map{|i| "c#{i}".to_sym} unless @cols.nil?
|
557
519
|
@bud_instance.coll_expr(coll_name.to_sym, expr, cols)
|
558
520
|
coll = @bud_instance.send(coll_name)
|
559
521
|
coll
|
@@ -570,13 +532,13 @@ module Bud
|
|
570
532
|
def pending_merge(o) # :nodoc: all
|
571
533
|
toplevel = @bud_instance.toplevel
|
572
534
|
if o.class <= Bud::PushElement
|
573
|
-
|
535
|
+
add_merge_target
|
574
536
|
o.wire_to_pending self
|
575
537
|
elsif o.class <= Bud::BudCollection
|
576
|
-
|
538
|
+
add_merge_target
|
577
539
|
o.pro.wire_to_pending self
|
578
540
|
elsif o.class <= Proc and toplevel.done_bootstrap and not toplevel.done_wiring
|
579
|
-
|
541
|
+
add_merge_target
|
580
542
|
tbl = register_coll_expr(o) unless o.nil?
|
581
543
|
tbl.pro.wire_to_pending self
|
582
544
|
else
|
@@ -599,7 +561,7 @@ module Bud
|
|
599
561
|
end
|
600
562
|
|
601
563
|
def tick
|
602
|
-
raise "tick must be overriden in #{self.class}"
|
564
|
+
raise Bud::Error, "tick must be overriden in #{self.class}"
|
603
565
|
end
|
604
566
|
|
605
567
|
# move deltas to storage, and new_deltas to deltas.
|
@@ -609,12 +571,15 @@ module Bud
|
|
609
571
|
unless @delta.empty?
|
610
572
|
puts "#{qualified_tabname}.tick_delta delta --> storage (#{@delta.size} elems)" if $BUD_DEBUG
|
611
573
|
@storage.merge!(@delta)
|
612
|
-
@tick_delta += @delta.values
|
574
|
+
@tick_delta += @delta.values if accumulate_tick_deltas
|
613
575
|
@delta.clear
|
614
576
|
end
|
615
577
|
|
616
578
|
unless @new_delta.empty?
|
617
579
|
puts "#{qualified_tabname}.tick_delta new_delta --> delta (#{@new_delta.size} elems)" if $BUD_DEBUG
|
580
|
+
|
581
|
+
# XXX: what about multiple delta tuples produced in the same tick that
|
582
|
+
# conflict on the PK?
|
618
583
|
@new_delta.each_pair do |k, v|
|
619
584
|
sv = @storage[k]
|
620
585
|
if sv.nil?
|
@@ -631,8 +596,9 @@ module Bud
|
|
631
596
|
|
632
597
|
public
|
633
598
|
def add_rescan_invalidate(rescan, invalidate)
|
634
|
-
# No change. Most collections don't need to rescan on every tick (only do
|
635
|
-
#
|
599
|
+
# No change. Most collections don't need to rescan on every tick (only do
|
600
|
+
# so on negate). Also, there's no cache to invalidate by default.
|
601
|
+
# Scratches and PushElements override this method.
|
636
602
|
end
|
637
603
|
|
638
604
|
def bootstrap
|
@@ -648,9 +614,9 @@ module Bud
|
|
648
614
|
puts "#{qualified_tabname}.flush delta --> storage" unless @delta.empty?
|
649
615
|
puts "#{qualified_tabname}.flush new_delta --> storage" unless @new_delta.empty?
|
650
616
|
end
|
651
|
-
unless
|
617
|
+
unless @delta.empty?
|
652
618
|
@storage.merge!(@delta)
|
653
|
-
@tick_delta += @delta.values
|
619
|
+
@tick_delta += @delta.values if accumulate_tick_deltas
|
654
620
|
@delta.clear
|
655
621
|
end
|
656
622
|
unless @new_delta.empty?
|
@@ -664,7 +630,6 @@ module Bud
|
|
664
630
|
def to_push_elem(the_name=tabname, the_schema=schema)
|
665
631
|
# if no push source yet, set one up
|
666
632
|
toplevel = @bud_instance.toplevel
|
667
|
-
#rule_context = toplevel.this_rule_context
|
668
633
|
this_stratum = toplevel.this_stratum
|
669
634
|
oid = self.object_id
|
670
635
|
unless toplevel.scanners[this_stratum][[oid, the_name]]
|
@@ -674,17 +639,6 @@ module Bud
|
|
674
639
|
return toplevel.scanners[this_stratum][[oid, the_name]]
|
675
640
|
end
|
676
641
|
|
677
|
-
private
|
678
|
-
def method_missing(sym, *args, &block)
|
679
|
-
begin
|
680
|
-
@storage.send sym, *args, &block
|
681
|
-
rescue Exception => e
|
682
|
-
err = NoMethodError.new("no method :#{sym} in class #{self.class.name}")
|
683
|
-
err.set_backtrace(e.backtrace)
|
684
|
-
raise err
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
642
|
######## aggs
|
689
643
|
|
690
644
|
private
|
@@ -699,16 +653,14 @@ module Bud
|
|
699
653
|
end
|
700
654
|
end
|
701
655
|
|
702
|
-
|
703
656
|
# a generalization of argmin/argmax to arbitrary exemplary aggregates.
|
704
657
|
# for each distinct value of the grouping key columns, return the items in that group
|
705
658
|
# that have the value of the exemplary aggregate +aggname+
|
706
659
|
public
|
707
660
|
def argagg(aggname, gbkey_cols, collection)
|
708
661
|
elem = to_push_elem
|
709
|
-
elem.schema
|
710
662
|
gbkey_cols = gbkey_cols.map{|k| canonicalize_col(k)} unless gbkey_cols.nil?
|
711
|
-
retval = elem.argagg(aggname,gbkey_cols,canonicalize_col(collection))
|
663
|
+
retval = elem.argagg(aggname, gbkey_cols, canonicalize_col(collection))
|
712
664
|
# PushElement inherits the schema accessors from this Collection
|
713
665
|
retval.extend @cols_access
|
714
666
|
retval
|
@@ -722,37 +674,21 @@ module Bud
|
|
722
674
|
argagg(:min, gbkey_cols, col)
|
723
675
|
end
|
724
676
|
|
725
|
-
# for each distinct value of the grouping key columns, return the
|
726
|
-
# that group that
|
677
|
+
# for each distinct value of the grouping key columns, return the items in
|
678
|
+
# that group that have the maximum value of the attribute +col+. Note that
|
727
679
|
# multiple tuples might be returned.
|
728
680
|
public
|
729
681
|
def argmax(gbkey_cols, col)
|
730
682
|
argagg(:max, gbkey_cols, col)
|
731
683
|
end
|
732
684
|
|
733
|
-
private
|
734
|
-
def wrap_map(j, &blk)
|
735
|
-
if blk.nil?
|
736
|
-
return j
|
737
|
-
else
|
738
|
-
return j.map(&blk)
|
739
|
-
end
|
740
|
-
end
|
741
|
-
|
742
|
-
# def join(collections, *preds, &blk)
|
743
|
-
# # since joins are stateful, we want to allocate them once and store in this Bud instance
|
744
|
-
# # we ID them on their tablenames, preds, and block
|
745
|
-
# return wrap_map(BudJoin.new(collections, @bud_instance, preds), &blk)
|
746
|
-
# end
|
747
|
-
|
748
685
|
# form a collection containing all pairs of items in +self+ and items in
|
749
686
|
# +collection+
|
750
687
|
public
|
751
688
|
def *(collection)
|
752
|
-
elem1
|
689
|
+
elem1 = to_push_elem
|
753
690
|
j = elem1.join(collection)
|
754
691
|
return j
|
755
|
-
# join([self, collection])
|
756
692
|
end
|
757
693
|
|
758
694
|
def group(key_cols, *aggpairs, &blk)
|
@@ -778,14 +714,14 @@ module Bud
|
|
778
714
|
elem1 = to_push_elem
|
779
715
|
red_elem = elem1.reduce(initial, &blk)
|
780
716
|
return red_elem
|
781
|
-
end
|
717
|
+
end
|
782
718
|
|
783
719
|
public
|
784
720
|
def pretty_print_instance_variables
|
785
721
|
# list of attributes (in order) to print when pretty_print is called.
|
786
722
|
important = ["@tabname", "@storage", "@delta", "@new_delta", "@pending"]
|
787
723
|
# everything except bud_instance
|
788
|
-
important + (self.instance_variables - important - ["@bud_instance"])
|
724
|
+
important + (self.instance_variables - important - ["@bud_instance"])
|
789
725
|
end
|
790
726
|
|
791
727
|
public
|
@@ -796,9 +732,12 @@ module Bud
|
|
796
732
|
end
|
797
733
|
|
798
734
|
class BudScratch < BudCollection # :nodoc: all
|
735
|
+
def accumulate_tick_deltas
|
736
|
+
false
|
737
|
+
end
|
738
|
+
|
799
739
|
public
|
800
740
|
def tick # :nodoc: all
|
801
|
-
@tick_delta.clear
|
802
741
|
@delta.clear
|
803
742
|
if not @pending.empty?
|
804
743
|
invalidate_cache
|
@@ -815,20 +754,19 @@ module Bud
|
|
815
754
|
is_source # rescan always only if this scratch is a source.
|
816
755
|
end
|
817
756
|
|
818
|
-
|
819
757
|
public
|
820
758
|
def add_rescan_invalidate(rescan, invalidate)
|
821
759
|
srcs = non_temporal_predecessors
|
822
760
|
if srcs.any? {|e| rescan.member? e}
|
823
761
|
invalidate << self
|
824
|
-
|
762
|
+
rescan += srcs
|
825
763
|
end
|
826
764
|
end
|
827
765
|
|
828
766
|
public
|
829
767
|
def invalidate_cache
|
830
768
|
puts "#{qualified_tabname} invalidated" if $BUD_DEBUG
|
831
|
-
#for scratches, storage is a cached value
|
769
|
+
# for scratches, storage is a cached value
|
832
770
|
@invalidated = true
|
833
771
|
@storage.clear
|
834
772
|
end
|
@@ -843,9 +781,10 @@ module Bud
|
|
843
781
|
class BudTemp < BudScratch # :nodoc: all
|
844
782
|
end
|
845
783
|
|
846
|
-
# Channels are a different type of collection in that they represent two
|
847
|
-
# incoming and outgoing. The incoming side
|
848
|
-
#
|
784
|
+
# Channels are a different type of collection in that they represent two
|
785
|
+
# distinct collections, one each for incoming and outgoing. The incoming side
|
786
|
+
# makes use of @storage and @delta, whereas the outgoing side only deals with
|
787
|
+
# @pending. XXX Maybe we should be using aliases instead.
|
849
788
|
class BudChannel < BudCollection
|
850
789
|
attr_reader :locspec_idx # :nodoc: all
|
851
790
|
|
@@ -908,15 +847,10 @@ module Bud
|
|
908
847
|
lsplit[1] = lsplit[1].to_i
|
909
848
|
return lsplit
|
910
849
|
rescue Exception => e
|
911
|
-
raise Bud::Error, "
|
850
|
+
raise Bud::Error, "illegal location specifier in tuple #{t.inspect} for channel \"#{qualified_tabname}\": #{e.to_s}"
|
912
851
|
end
|
913
852
|
end
|
914
853
|
|
915
|
-
public
|
916
|
-
def clone_empty
|
917
|
-
self.class.new(tabname, bud_instance, @raw_schema, @is_loopback)
|
918
|
-
end
|
919
|
-
|
920
854
|
public
|
921
855
|
def tick # :nodoc: all
|
922
856
|
@storage.clear
|
@@ -968,7 +902,7 @@ module Bud
|
|
968
902
|
end
|
969
903
|
|
970
904
|
superator "<~" do |o|
|
971
|
-
if o.class <= PushElement
|
905
|
+
if o.class <= Bud::PushElement
|
972
906
|
o.wire_to_pending self
|
973
907
|
else
|
974
908
|
pending_merge(o)
|
@@ -1066,7 +1000,7 @@ module Bud
|
|
1066
1000
|
end
|
1067
1001
|
|
1068
1002
|
superator "<~" do |o|
|
1069
|
-
if o.class <= PushElement
|
1003
|
+
if o.class <= Bud::PushElement
|
1070
1004
|
o.wire_to_pending self
|
1071
1005
|
else
|
1072
1006
|
pending_merge(o)
|
@@ -1118,7 +1052,7 @@ module Bud
|
|
1118
1052
|
|
1119
1053
|
public
|
1120
1054
|
def invalidate_cache
|
1121
|
-
raise "
|
1055
|
+
raise Bud::Error, "abstract method not implemented by derived class #{self.class}"
|
1122
1056
|
end
|
1123
1057
|
end
|
1124
1058
|
|
@@ -1149,13 +1083,13 @@ module Bud
|
|
1149
1083
|
deleted ||= v
|
1150
1084
|
end
|
1151
1085
|
|
1152
|
-
@invalidated =
|
1086
|
+
@invalidated = (not deleted.nil?)
|
1153
1087
|
puts "table #{qualified_tabname} invalidated" if $BUD_DEBUG and @invalidated
|
1154
1088
|
|
1155
1089
|
@pending.each do |keycols, tuple|
|
1156
1090
|
old = @storage[keycols]
|
1157
1091
|
if old.nil?
|
1158
|
-
@delta[keycols] = tuple
|
1092
|
+
@delta[keycols] = tuple
|
1159
1093
|
else
|
1160
1094
|
raise_pk_error(tuple, old) unless tuple == old
|
1161
1095
|
end
|
@@ -1166,19 +1100,19 @@ module Bud
|
|
1166
1100
|
end
|
1167
1101
|
|
1168
1102
|
def invalidated=(val)
|
1169
|
-
raise "Internal error:
|
1103
|
+
raise "Internal error: must not set invalidate on tables"
|
1170
1104
|
end
|
1171
1105
|
|
1172
1106
|
def pending_delete(o)
|
1173
1107
|
toplevel = @bud_instance.toplevel
|
1174
1108
|
if o.class <= Bud::PushElement
|
1175
|
-
|
1109
|
+
add_merge_target
|
1176
1110
|
o.wire_to_delete self
|
1177
1111
|
elsif o.class <= Bud::BudCollection
|
1178
|
-
|
1112
|
+
add_merge_target
|
1179
1113
|
o.pro.wire_to_delete self
|
1180
1114
|
elsif o.class <= Proc and @bud_instance.toplevel.done_bootstrap and not toplevel.done_wiring
|
1181
|
-
|
1115
|
+
add_merge_target
|
1182
1116
|
tbl = register_coll_expr(o)
|
1183
1117
|
tbl.pro.wire_to_delete self
|
1184
1118
|
else
|
@@ -1217,8 +1151,9 @@ module Bud
|
|
1217
1151
|
|
1218
1152
|
public
|
1219
1153
|
def invalidate_cache
|
1220
|
-
#
|
1221
|
-
#
|
1154
|
+
# No cache to invalidate. Also, tables do not invalidate dependents,
|
1155
|
+
# because their own state is not considered invalidated; that happens only
|
1156
|
+
# if there were pending deletes at the beginning of a tick (see tick())
|
1222
1157
|
puts "******** invalidate_cache called on BudTable"
|
1223
1158
|
end
|
1224
1159
|
|
@@ -1226,8 +1161,8 @@ module Bud
|
|
1226
1161
|
superator "<+-" do |o|
|
1227
1162
|
pending_delete_keys(o)
|
1228
1163
|
self <+ o
|
1229
|
-
end
|
1230
|
-
public
|
1164
|
+
end
|
1165
|
+
public
|
1231
1166
|
superator "<-+" do |o|
|
1232
1167
|
self <+- o
|
1233
1168
|
end
|
@@ -1251,20 +1186,6 @@ module Bud
|
|
1251
1186
|
end
|
1252
1187
|
end
|
1253
1188
|
|
1254
|
-
class BudSignal < BudReadOnly
|
1255
|
-
def invalidate_at_tick
|
1256
|
-
true
|
1257
|
-
end
|
1258
|
-
def tick
|
1259
|
-
@invalidated = true
|
1260
|
-
@storage.clear
|
1261
|
-
unless @pending.empty?
|
1262
|
-
@delta = @pending
|
1263
|
-
@pending = {}
|
1264
|
-
end
|
1265
|
-
end
|
1266
|
-
end
|
1267
|
-
|
1268
1189
|
class BudCollExpr < BudReadOnly # :nodoc: all
|
1269
1190
|
def initialize(name, bud_instance, expr, given_schema=nil, defer_schema=false)
|
1270
1191
|
super(name, bud_instance, given_schema, defer_schema)
|
@@ -1309,20 +1230,12 @@ module Bud
|
|
1309
1230
|
|
1310
1231
|
public
|
1311
1232
|
def each(&blk)
|
1312
|
-
each_raw {|l|
|
1233
|
+
each_raw {|l| blk.call(l)}
|
1313
1234
|
end
|
1314
1235
|
end
|
1315
1236
|
end
|
1316
1237
|
|
1317
1238
|
module Enumerable
|
1318
|
-
# public
|
1319
|
-
# # monkeypatch to Enumerable to rename collections and their schemas
|
1320
|
-
# def rename(new_tabname, new_schema=nil)
|
1321
|
-
# scr = Bud::BudScratch.new(new_tabname.to_s, nil, new_schema)
|
1322
|
-
# scr.merge(self, scr.storage)
|
1323
|
-
# scr
|
1324
|
-
# end
|
1325
|
-
|
1326
1239
|
public
|
1327
1240
|
# We rewrite "map" calls in Bloom blocks to invoke the "pro" method
|
1328
1241
|
# instead. This is fine when applied to a BudCollection; when applied to a
|
data/lib/bud/errors.rb
CHANGED
@@ -12,7 +12,11 @@ module Bud
|
|
12
12
|
# Raised when the input program fails to compile (e.g., due to illegal
|
13
13
|
# syntax).
|
14
14
|
class CompileError < Error; end
|
15
|
+
|
16
|
+
# Raised when the program is given in an illegal location (e.g., presented as
|
17
|
+
# an eval block).
|
18
|
+
class IllegalSourceError < Error; end
|
15
19
|
|
16
|
-
# Raised when evaluation halts with outstanding callbacks
|
20
|
+
# Raised when evaluation halts with outstanding callbacks.
|
17
21
|
class ShutdownWithCallbacksError < Error; end
|
18
22
|
end
|