bud 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
data/History.txt
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
== 0.9.
|
1
|
+
== 0.9.1 / 2012-04-10
|
2
|
+
|
3
|
+
* Reject attempts to insert a tuple into a collection with more fields than are
|
4
|
+
in the collection's schema
|
5
|
+
* Previous behavior was to ignore additional fields, but this was found to be
|
6
|
+
error-prone
|
7
|
+
* Remove builtin support for BUST (web services API); this avoids the need to
|
8
|
+
depend on the json, nestful and i18n gems.
|
9
|
+
|
10
|
+
== 0.9.0 / 2012-03-21
|
2
11
|
|
3
12
|
* Major performance enhancements
|
4
13
|
* Much, much faster: rewritten runtime that now uses a push-based dataflow
|
data/docs/cheat.md
CHANGED
@@ -295,14 +295,14 @@ Like `pairs`, but implicitly includes a block that projects down to the left ite
|
|
295
295
|
`rights(`*hash pairs*`)`:
|
296
296
|
Like `pairs`, but implicitly includes a block that projects down to the right item in each pair.
|
297
297
|
|
298
|
+
`outer(`*hash pairs*`)`:<br>
|
299
|
+
Left Outer Join. Like `pairs`, but items in the first collection will be produced nil-padded if they have no match in the second collection.
|
300
|
+
|
298
301
|
`flatten`:<br>
|
299
302
|
`flatten` is a bit like SQL's `SELECT *`: it produces a collection of concatenated objects, with a schema that is the concatenation of the schemas in tablelist (with duplicate names disambiguated). Useful for chaining to operators that expect input collections with schemas, e.g., `group`:
|
300
303
|
|
301
304
|
out <= (r * s).matches.flatten.group([:a], max(:b))
|
302
305
|
|
303
|
-
`outer(`*hash pairs*`)`:<br>
|
304
|
-
Left Outer Join. Like `pairs`, but items in the first collection will be produced nil-padded if they have no match in the second collection.
|
305
|
-
|
306
306
|
## Temp Collections ##
|
307
307
|
`temp`<br>
|
308
308
|
Temp collections are scratches defined within a `bloom` block:
|
File without changes
|
data/lib/bud/bud_meta.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'bud/rewrite'
|
2
|
-
require 'pp'
|
3
2
|
|
4
3
|
|
5
4
|
class BudMeta #:nodoc: all
|
@@ -16,9 +15,12 @@ class BudMeta #:nodoc: all
|
|
16
15
|
if @bud_instance.toplevel == @bud_instance
|
17
16
|
nodes, stratum_map, top_stratum = stratify_preds
|
18
17
|
|
19
|
-
# stratum_map = {fully qualified pred
|
18
|
+
# stratum_map = {fully qualified pred => stratum}. Copy stratum_map data
|
19
|
+
# into t_stratum format.
|
20
|
+
raise unless @bud_instance.t_stratum.to_a.empty?
|
21
|
+
@bud_instance.t_stratum <= stratum_map.to_a
|
20
22
|
|
21
|
-
#slot each rule into the stratum corresponding to its lhs pred (from stratum_map)
|
23
|
+
# slot each rule into the stratum corresponding to its lhs pred (from stratum_map)
|
22
24
|
stratified_rules = Array.new(top_stratum + 2) { [] } # stratum -> [ rules ]
|
23
25
|
@bud_instance.t_rules.each do |rule|
|
24
26
|
if rule.op.to_s == '<='
|
@@ -70,8 +72,11 @@ class BudMeta #:nodoc: all
|
|
70
72
|
pt = klass.__bloom_asts__[block_name]
|
71
73
|
return if pt.nil?
|
72
74
|
|
73
|
-
pt = Marshal.load(Marshal.dump(pt)) #deep
|
74
|
-
|
75
|
+
pt = Marshal.load(Marshal.dump(pt)) # deep copy because RuleRewriter mucks up pt
|
76
|
+
if @bud_instance.options[:dump_ast]
|
77
|
+
require 'pp'
|
78
|
+
pp pt
|
79
|
+
end
|
75
80
|
tmp_expander = TempExpander.new
|
76
81
|
pt = tmp_expander.process(pt)
|
77
82
|
tmp_expander.tmp_tables.each do |t|
|
@@ -104,9 +109,9 @@ class BudMeta #:nodoc: all
|
|
104
109
|
|
105
110
|
def get_qual_name(pt)
|
106
111
|
# expect to see a parse tree corresponding to a dotted name
|
107
|
-
# a.b.c == s(:call, s1,
|
108
|
-
# where s1 == s(:call, s2,
|
109
|
-
# where s2 == s(:call, nil
|
112
|
+
# a.b.c == s(:call, s1, :c, (:args))
|
113
|
+
# where s1 == s(:call, s2, :b, (:args))
|
114
|
+
# where s2 == s(:call, nil, :a, (:args))
|
110
115
|
|
111
116
|
tag, recv, name, args = pt
|
112
117
|
return nil unless tag == :call or args.length == 1
|
@@ -114,7 +119,7 @@ class BudMeta #:nodoc: all
|
|
114
119
|
if recv
|
115
120
|
qn = get_qual_name(recv)
|
116
121
|
return nil if qn.nil? or qn.size == 0
|
117
|
-
qn = qn
|
122
|
+
qn = "#{qn}.#{name}"
|
118
123
|
else
|
119
124
|
qn = name.to_s
|
120
125
|
end
|
@@ -147,11 +152,12 @@ class BudMeta #:nodoc: all
|
|
147
152
|
return pt unless n.sexp_type == :call and n.length == 4
|
148
153
|
|
149
154
|
# Rule format: call tag, lhs, op, rhs
|
150
|
-
|
155
|
+
_, lhs, op, rhs = n
|
151
156
|
|
152
157
|
# Check that LHS references a named collection
|
153
158
|
lhs_name = get_qual_name(lhs)
|
154
|
-
|
159
|
+
return [n, "Unexpected lhs format: #{lhs}"] if lhs.nil?
|
160
|
+
unless @bud_instance.tables.has_key? lhs_name.to_sym
|
155
161
|
return [n, "Collection does not exist: '#{lhs_name}'"]
|
156
162
|
end
|
157
163
|
|
@@ -242,19 +248,21 @@ class BudMeta #:nodoc: all
|
|
242
248
|
preds_in_body = nodes.select {|_, node| node.in_body}.map {|name, _| name}.to_set
|
243
249
|
|
244
250
|
bud = @bud_instance
|
251
|
+
out = bud.options[:stdout]
|
252
|
+
out ||= $stdout
|
245
253
|
bud.t_provides.each do |p|
|
246
254
|
pred, input = p.interface, p.input
|
247
255
|
if input
|
248
256
|
unless preds_in_body.include? pred.to_s
|
249
257
|
# input interface is underspecified if not used in any rule body
|
250
258
|
bud.t_underspecified << [pred, true] # true indicates input mode
|
251
|
-
puts "Warning: input interface #{pred} not used"
|
259
|
+
out.puts "Warning: input interface #{pred} not used"
|
252
260
|
end
|
253
261
|
else
|
254
262
|
unless preds_in_lhs.include? pred.to_s
|
255
263
|
# output interface underspecified if not in any rule's lhs
|
256
264
|
bud.t_underspecified << [pred, false] #false indicates output mode.
|
257
|
-
puts "Warning: output interface #{pred} not used"
|
265
|
+
out.puts "Warning: output interface #{pred} not used"
|
258
266
|
end
|
259
267
|
end
|
260
268
|
end
|
data/lib/bud/collections.rb
CHANGED
@@ -21,10 +21,9 @@ module Bud
|
|
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
|
24
|
-
|
25
|
-
attr_accessor :invalidated, :
|
24
|
+
attr_reader :wired_by, :to_delete
|
25
|
+
attr_accessor :invalidated, :rescan
|
26
26
|
attr_accessor :is_source
|
27
|
-
attr_accessor :wired_by
|
28
27
|
attr_accessor :accumulate_tick_deltas # updated in bud.do_wiring
|
29
28
|
|
30
29
|
def initialize(name, bud_instance, given_schema=nil, defer_schema=false) # :nodoc: all
|
@@ -50,6 +49,7 @@ module Bud
|
|
50
49
|
given_schema ||= {[:key]=>[:val]}
|
51
50
|
@given_schema = given_schema
|
52
51
|
@cols, @key_cols = BudCollection.parse_schema(given_schema)
|
52
|
+
|
53
53
|
# Check that no location specifiers appear in the schema. In the case of
|
54
54
|
# channels, the location specifier has already been stripped from the
|
55
55
|
# user-specified schema.
|
@@ -59,18 +59,19 @@ module Bud
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
62
|
+
@key_colnums = @key_cols.map {|k| @cols.index(k)}
|
63
|
+
|
64
|
+
if @cols.empty?
|
63
65
|
@cols = nil
|
64
66
|
else
|
65
67
|
@struct = ($struct_classes[@cols] ||= Struct.new(*@cols))
|
66
68
|
@structlen = @struct.members.length
|
67
69
|
end
|
68
|
-
@key_colnums = key_cols.map {|k| @cols.index(k)}
|
69
70
|
setup_accessors
|
70
71
|
end
|
71
72
|
|
72
73
|
def qualified_tabname
|
73
|
-
@qualified_tabname ||= @bud_instance.toplevel? ? tabname :
|
74
|
+
@qualified_tabname ||= @bud_instance.toplevel? ? tabname : "#{@bud_instance.qualified_name}.#{tabname}".to_sym
|
74
75
|
end
|
75
76
|
|
76
77
|
# The user-specified schema might come in two forms: a hash of Array =>
|
@@ -168,7 +169,7 @@ module Bud
|
|
168
169
|
# project the collection to its key attributes
|
169
170
|
public
|
170
171
|
def keys
|
171
|
-
self.pro{|t|
|
172
|
+
self.pro{|t| get_key_vals(t)}
|
172
173
|
end
|
173
174
|
|
174
175
|
# project the collection to its non-key attributes
|
@@ -181,33 +182,19 @@ module Bud
|
|
181
182
|
public
|
182
183
|
def inspected
|
183
184
|
self.pro{|t| [t.inspect]}
|
184
|
-
# how about when this is called outside wiring?
|
185
|
-
# [["#{@tabname}: [#{self.map{|t| "\n (#{t.map{|v| v.inspect}.join ", "})"}}]"]]
|
186
185
|
end
|
187
186
|
|
188
187
|
# projection
|
189
188
|
public
|
190
189
|
def pro(the_name=tabname, the_schema=schema, &blk)
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
public
|
199
|
-
def each_with_index(the_name=tabname, the_schema=schema, &blk)
|
200
|
-
toplevel = @bud_instance.toplevel
|
201
|
-
if not toplevel.done_wiring
|
202
|
-
proj = pro(the_name, the_schema)
|
203
|
-
elem = Bud::PushEachWithIndex.new('each_with_index' + object_id.to_s,
|
204
|
-
toplevel.this_rule_context, tabname)
|
205
|
-
elem.set_block(&blk)
|
206
|
-
proj.wire_to(elem)
|
207
|
-
toplevel.push_elems[[self.object_id, :each, blk]] = elem
|
208
|
-
elem
|
190
|
+
if @bud_instance.wiring?
|
191
|
+
pusher = to_push_elem(the_name, the_schema)
|
192
|
+
pusher_pro = pusher.pro(&blk)
|
193
|
+
pusher_pro.elem_name = the_name
|
194
|
+
pusher_pro.tabname = the_name
|
195
|
+
pusher_pro
|
209
196
|
else
|
210
|
-
|
197
|
+
@storage.map(&blk)
|
211
198
|
end
|
212
199
|
end
|
213
200
|
|
@@ -217,40 +204,42 @@ module Bud
|
|
217
204
|
# accum.
|
218
205
|
public
|
219
206
|
def flat_map(&blk)
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
207
|
+
if @bud_instance.wiring?
|
208
|
+
pusher = self.pro(&blk)
|
209
|
+
toplevel = @bud_instance.toplevel
|
210
|
+
elem = Bud::PushElement.new(tabname, toplevel.this_rule_context, tabname)
|
211
|
+
pusher.wire_to(elem)
|
212
|
+
f = Proc.new do |t|
|
213
|
+
t.each do |i|
|
214
|
+
elem.push_out(i, false)
|
215
|
+
end
|
216
|
+
nil
|
227
217
|
end
|
228
|
-
|
218
|
+
elem.set_block(&f)
|
219
|
+
toplevel.push_elems[[self.object_id, :flatten]] = elem
|
220
|
+
return elem
|
221
|
+
else
|
222
|
+
@storage.flat_map(&blk)
|
229
223
|
end
|
230
|
-
elem.set_block(&f)
|
231
|
-
toplevel.push_elems[[self.object_id, :flatten]] = elem
|
232
|
-
return elem
|
233
224
|
end
|
234
225
|
|
235
226
|
public
|
236
227
|
def sort(&blk)
|
237
|
-
|
238
|
-
|
228
|
+
if @bud_instance.wiring?
|
229
|
+
pusher = self.pro
|
230
|
+
pusher.sort("sort#{object_id}", @bud_instance, @cols, &blk)
|
231
|
+
else
|
232
|
+
@storage.sort
|
233
|
+
end
|
239
234
|
end
|
240
235
|
|
241
|
-
def rename(the_name, the_schema=nil)
|
236
|
+
def rename(the_name, the_schema=nil, &blk)
|
237
|
+
raise unless @bud_instance.wiring?
|
242
238
|
# a scratch with this name should have been defined during rewriting
|
243
|
-
raise
|
244
|
-
|
245
|
-
#retval.init_schema(the_schema)
|
246
|
-
retval
|
239
|
+
raise Bud::Error, "rename failed to define a scratch named #{the_name}" unless @bud_instance.respond_to? the_name
|
240
|
+
pro(the_name, the_schema, &blk)
|
247
241
|
end
|
248
242
|
|
249
|
-
# def to_enum
|
250
|
-
# pusher = self.pro
|
251
|
-
# pusher.to_enum
|
252
|
-
# end
|
253
|
-
|
254
243
|
# By default, all tuples in any rhs are in storage or delta. Tuples in
|
255
244
|
# new_delta will get transitioned to delta in the next iteration of the
|
256
245
|
# evaluator (but within the current time tick).
|
@@ -377,9 +366,9 @@ module Bud
|
|
377
366
|
end
|
378
367
|
|
379
368
|
private
|
380
|
-
def raise_pk_error(
|
369
|
+
def raise_pk_error(new, old)
|
381
370
|
key = get_key_vals(old)
|
382
|
-
raise Bud::KeyConstraintError, "key conflict inserting #{
|
371
|
+
raise Bud::KeyConstraintError, "key conflict inserting #{new.inspect} into \"#{tabname}\": existing tuple #{old.inspect}, key = #{key.inspect}"
|
383
372
|
end
|
384
373
|
|
385
374
|
private
|
@@ -396,7 +385,9 @@ module Bud
|
|
396
385
|
raise Bud::TypeError, "array or struct type expected in \"#{qualified_tabname}\": #{o.inspect}"
|
397
386
|
end
|
398
387
|
|
399
|
-
|
388
|
+
if o.length > @structlen
|
389
|
+
raise Bud::TypeError, "too many columns for \"#{qualified_tabname}\": #{o.inspect}"
|
390
|
+
end
|
400
391
|
return @struct.new(*o)
|
401
392
|
end
|
402
393
|
|
@@ -406,7 +397,7 @@ module Bud
|
|
406
397
|
end
|
407
398
|
|
408
399
|
public
|
409
|
-
def do_insert(
|
400
|
+
def do_insert(t, store)
|
410
401
|
if $BUD_DEBUG
|
411
402
|
storetype = case store.object_id
|
412
403
|
when @storage.object_id; "storage"
|
@@ -414,17 +405,22 @@ module Bud
|
|
414
405
|
when @delta.object_id; "delta"
|
415
406
|
when @new_delta.object_id; "new_delta"
|
416
407
|
end
|
417
|
-
puts "#{qualified_tabname}.#{storetype} ==> #{
|
408
|
+
puts "#{qualified_tabname}.#{storetype} ==> #{t}"
|
418
409
|
end
|
419
|
-
return if
|
420
|
-
|
421
|
-
key = get_key_vals(
|
410
|
+
return if t.nil? # silently ignore nils resulting from map predicates failing
|
411
|
+
t = prep_tuple(t)
|
412
|
+
key = get_key_vals(t)
|
413
|
+
merge_to_buf(store, key, t, store[key])
|
414
|
+
end
|
422
415
|
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
416
|
+
# Merge "tup" with key values "key" into "buf". "old" is an existing tuple
|
417
|
+
# with the same key columns as "tup" (if any such tuple exists).
|
418
|
+
private
|
419
|
+
def merge_to_buf(buf, key, tup, old)
|
420
|
+
if old.nil? # no matching tuple found
|
421
|
+
buf[key] = tup
|
422
|
+
elsif old != tup # ignore duplicates
|
423
|
+
raise_pk_error(tup, old)
|
428
424
|
end
|
429
425
|
end
|
430
426
|
|
@@ -487,9 +483,13 @@ module Bud
|
|
487
483
|
end
|
488
484
|
end
|
489
485
|
|
486
|
+
# This is used for two quite different purposes. If given a Bud collection
|
487
|
+
# or dataflow element as an input, we assume we're being called to wire up
|
488
|
+
# the push-based dataflow. If given an Enumerable consisting of Bud tuples,
|
489
|
+
# we assume we're being called to insert the tuples (e.g., to support direct
|
490
|
+
# insertion of tuples into Bud collections in a sync_do block).
|
490
491
|
public
|
491
492
|
def merge(o, buf=@delta) # :nodoc: all
|
492
|
-
toplevel = @bud_instance.toplevel
|
493
493
|
if o.class <= Bud::PushElement
|
494
494
|
add_merge_target
|
495
495
|
deduce_schema(o) if @cols.nil?
|
@@ -498,7 +498,7 @@ module Bud
|
|
498
498
|
add_merge_target
|
499
499
|
deduce_schema(o) if @cols.nil?
|
500
500
|
o.pro.wire_to self
|
501
|
-
elsif o.class <= Proc
|
501
|
+
elsif o.class <= Proc
|
502
502
|
add_merge_target
|
503
503
|
tbl = register_coll_expr(o)
|
504
504
|
tbl.pro.wire_to self
|
@@ -510,15 +510,13 @@ module Bud
|
|
510
510
|
o.each {|i| do_insert(i, buf)}
|
511
511
|
end
|
512
512
|
end
|
513
|
-
return self
|
514
513
|
end
|
515
514
|
|
516
515
|
def register_coll_expr(expr)
|
517
516
|
coll_name = "expr_#{expr.object_id}"
|
518
517
|
cols = (1..@cols.length).map{|i| "c#{i}".to_sym} unless @cols.nil?
|
519
518
|
@bud_instance.coll_expr(coll_name.to_sym, expr, cols)
|
520
|
-
|
521
|
-
coll
|
519
|
+
@bud_instance.send(coll_name)
|
522
520
|
end
|
523
521
|
|
524
522
|
public
|
@@ -530,26 +528,12 @@ module Bud
|
|
530
528
|
# buffer items to be merged atomically at end of this timestep
|
531
529
|
public
|
532
530
|
def pending_merge(o) # :nodoc: all
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
o.
|
537
|
-
|
538
|
-
add_merge_target
|
539
|
-
o.pro.wire_to_pending self
|
540
|
-
elsif o.class <= Proc and toplevel.done_bootstrap and not toplevel.done_wiring
|
541
|
-
add_merge_target
|
542
|
-
tbl = register_coll_expr(o) unless o.nil?
|
543
|
-
tbl.pro.wire_to_pending self
|
544
|
-
else
|
545
|
-
unless o.nil?
|
546
|
-
o = o.uniq.compact if o.respond_to?(:uniq)
|
547
|
-
check_enumerable(o)
|
548
|
-
establish_schema(o) if @cols.nil?
|
549
|
-
o.each{|i| self.do_insert(i, @pending)}
|
550
|
-
end
|
531
|
+
unless o.nil?
|
532
|
+
o = o.uniq.compact if o.respond_to?(:uniq)
|
533
|
+
check_enumerable(o)
|
534
|
+
establish_schema(o) if @cols.nil?
|
535
|
+
o.each{|i| self.do_insert(i, @pending)}
|
551
536
|
end
|
552
|
-
return self
|
553
537
|
end
|
554
538
|
|
555
539
|
public
|
@@ -557,7 +541,19 @@ module Bud
|
|
557
541
|
|
558
542
|
public
|
559
543
|
superator "<+" do |o|
|
560
|
-
|
544
|
+
if o.class <= Bud::PushElement
|
545
|
+
add_merge_target
|
546
|
+
o.wire_to(self, :pending)
|
547
|
+
elsif o.class <= Bud::BudCollection
|
548
|
+
add_merge_target
|
549
|
+
o.pro.wire_to(self, :pending)
|
550
|
+
elsif o.class <= Proc
|
551
|
+
add_merge_target
|
552
|
+
tbl = register_coll_expr(o)
|
553
|
+
tbl.pro.wire_to(self, :pending)
|
554
|
+
else
|
555
|
+
pending_merge(o)
|
556
|
+
end
|
561
557
|
end
|
562
558
|
|
563
559
|
def tick
|
@@ -578,15 +574,10 @@ module Bud
|
|
578
574
|
unless @new_delta.empty?
|
579
575
|
puts "#{qualified_tabname}.tick_delta new_delta --> delta (#{@new_delta.size} elems)" if $BUD_DEBUG
|
580
576
|
|
581
|
-
#
|
582
|
-
#
|
583
|
-
@new_delta.each_pair do |
|
584
|
-
|
585
|
-
if sv.nil?
|
586
|
-
@delta[k] = v
|
587
|
-
else
|
588
|
-
raise_pk_error(v, sv) unless v == sv
|
589
|
-
end
|
577
|
+
# NB: key conflicts between different new_delta tuples are detected in
|
578
|
+
# do_insert().
|
579
|
+
@new_delta.each_pair do |key, tup|
|
580
|
+
merge_to_buf(@delta, key, tup, @storage[key])
|
590
581
|
end
|
591
582
|
@new_delta.clear
|
592
583
|
return !(@delta.empty?)
|
@@ -633,8 +624,10 @@ module Bud
|
|
633
624
|
this_stratum = toplevel.this_stratum
|
634
625
|
oid = self.object_id
|
635
626
|
unless toplevel.scanners[this_stratum][[oid, the_name]]
|
636
|
-
|
637
|
-
|
627
|
+
scanner = Bud::ScannerElement.new(the_name, @bud_instance,
|
628
|
+
self, the_schema)
|
629
|
+
toplevel.scanners[this_stratum][[oid, the_name]] = scanner
|
630
|
+
toplevel.push_sources[this_stratum][[oid, the_name]] = scanner
|
638
631
|
end
|
639
632
|
return toplevel.scanners[this_stratum][[oid, the_name]]
|
640
633
|
end
|
@@ -709,11 +702,8 @@ module Bud
|
|
709
702
|
col.class <= Symbol ? self.send(col) : col
|
710
703
|
end
|
711
704
|
|
712
|
-
# alias reduce inject
|
713
705
|
def reduce(initial, &blk)
|
714
|
-
|
715
|
-
red_elem = elem1.reduce(initial, &blk)
|
716
|
-
return red_elem
|
706
|
+
return to_push_elem.reduce(initial, &blk)
|
717
707
|
end
|
718
708
|
|
719
709
|
public
|
@@ -867,17 +857,18 @@ module Bud
|
|
867
857
|
public
|
868
858
|
def flush # :nodoc: all
|
869
859
|
toplevel = @bud_instance.toplevel
|
870
|
-
ip = toplevel.ip
|
871
|
-
port = toplevel.port
|
872
860
|
@pending.each_value do |t|
|
873
861
|
if @is_loopback
|
862
|
+
ip = toplevel.ip
|
863
|
+
port = toplevel.port
|
874
864
|
the_locspec = [ip, port]
|
875
865
|
else
|
876
866
|
the_locspec = split_locspec(t, @locspec_idx)
|
877
867
|
raise Bud::Error, "'#{t[@locspec_idx]}', channel '#{@tabname}'" if the_locspec[0].nil? or the_locspec[1].nil? or the_locspec[0] == '' or the_locspec[1] == ''
|
878
868
|
end
|
879
869
|
puts "channel #{qualified_tabname}.send: #{t}" if $BUD_DEBUG
|
880
|
-
toplevel.dsock.send_datagram([qualified_tabname.to_s, t].to_msgpack,
|
870
|
+
toplevel.dsock.send_datagram([qualified_tabname.to_s, t].to_msgpack,
|
871
|
+
the_locspec[0], the_locspec[1])
|
881
872
|
end
|
882
873
|
@pending.clear
|
883
874
|
end
|
@@ -903,7 +894,12 @@ module Bud
|
|
903
894
|
|
904
895
|
superator "<~" do |o|
|
905
896
|
if o.class <= Bud::PushElement
|
906
|
-
o.
|
897
|
+
o.wire_to(self, :pending)
|
898
|
+
elsif o.class <= Bud::BudCollection
|
899
|
+
o.pro.wire_to(self, :pending)
|
900
|
+
elsif o.class <= Proc
|
901
|
+
tbl = register_coll_expr(o)
|
902
|
+
tbl.pro.wire_to(self, :pending)
|
907
903
|
else
|
908
904
|
pending_merge(o)
|
909
905
|
end
|
@@ -1001,7 +997,12 @@ module Bud
|
|
1001
997
|
|
1002
998
|
superator "<~" do |o|
|
1003
999
|
if o.class <= Bud::PushElement
|
1004
|
-
o.
|
1000
|
+
o.wire_to(self, :pending)
|
1001
|
+
elsif o.class <= Bud::BudCollection
|
1002
|
+
o.pro.wire_to(self, :pending)
|
1003
|
+
elsif o.class <= Proc
|
1004
|
+
tbl = register_coll_expr(o)
|
1005
|
+
tbl.pro.wire_to(self, :pending)
|
1005
1006
|
else
|
1006
1007
|
pending_merge(o)
|
1007
1008
|
end
|
@@ -1072,27 +1073,22 @@ module Bud
|
|
1072
1073
|
@tick_delta.clear
|
1073
1074
|
deleted = nil
|
1074
1075
|
@to_delete.each do |tuple|
|
1075
|
-
keycols =
|
1076
|
+
keycols = get_key_vals(tuple)
|
1076
1077
|
if @storage[keycols] == tuple
|
1077
1078
|
v = @storage.delete keycols
|
1078
1079
|
deleted ||= v
|
1079
1080
|
end
|
1080
1081
|
end
|
1081
1082
|
@to_delete_by_key.each do |tuple|
|
1082
|
-
v = @storage.delete
|
1083
|
+
v = @storage.delete(get_key_vals(tuple))
|
1083
1084
|
deleted ||= v
|
1084
1085
|
end
|
1085
1086
|
|
1086
1087
|
@invalidated = (not deleted.nil?)
|
1087
1088
|
puts "table #{qualified_tabname} invalidated" if $BUD_DEBUG and @invalidated
|
1088
1089
|
|
1089
|
-
@pending.each do |
|
1090
|
-
|
1091
|
-
if old.nil?
|
1092
|
-
@delta[keycols] = tuple
|
1093
|
-
else
|
1094
|
-
raise_pk_error(tuple, old) unless tuple == old
|
1095
|
-
end
|
1090
|
+
@pending.each do |key, tup|
|
1091
|
+
merge_to_buf(@delta, key, tup, @storage[key])
|
1096
1092
|
end
|
1097
1093
|
@to_delete = []
|
1098
1094
|
@to_delete_by_key = []
|
@@ -1100,21 +1096,20 @@ module Bud
|
|
1100
1096
|
end
|
1101
1097
|
|
1102
1098
|
def invalidated=(val)
|
1103
|
-
raise "
|
1099
|
+
raise Bud::Error, "internal error: must not set invalidate on tables"
|
1104
1100
|
end
|
1105
1101
|
|
1106
1102
|
def pending_delete(o)
|
1107
|
-
toplevel = @bud_instance.toplevel
|
1108
1103
|
if o.class <= Bud::PushElement
|
1109
1104
|
add_merge_target
|
1110
|
-
o.
|
1105
|
+
o.wire_to(self, :delete)
|
1111
1106
|
elsif o.class <= Bud::BudCollection
|
1112
1107
|
add_merge_target
|
1113
|
-
o.pro.
|
1114
|
-
elsif o.class <= Proc
|
1108
|
+
o.pro.wire_to(self, :delete)
|
1109
|
+
elsif o.class <= Proc
|
1115
1110
|
add_merge_target
|
1116
1111
|
tbl = register_coll_expr(o)
|
1117
|
-
tbl.pro.
|
1112
|
+
tbl.pro.wire_to(self, :delete)
|
1118
1113
|
else
|
1119
1114
|
unless o.nil?
|
1120
1115
|
o = o.uniq.compact if o.respond_to?(:uniq)
|
@@ -1130,14 +1125,13 @@ module Bud
|
|
1130
1125
|
|
1131
1126
|
public
|
1132
1127
|
def pending_delete_keys(o)
|
1133
|
-
toplevel = @bud_instance.toplevel
|
1134
1128
|
if o.class <= Bud::PushElement
|
1135
|
-
o.
|
1129
|
+
o.wire_to(self, :delete_by_key)
|
1136
1130
|
elsif o.class <= Bud::BudCollection
|
1137
|
-
o.pro.
|
1138
|
-
elsif o.class <= Proc
|
1131
|
+
o.pro.wire_to(self, :delete_by_key)
|
1132
|
+
elsif o.class <= Proc
|
1139
1133
|
tbl = register_coll_expr(o)
|
1140
|
-
tbl.pro.
|
1134
|
+
tbl.pro.wire_to(self, :delete_by_key)
|
1141
1135
|
else
|
1142
1136
|
unless o.nil?
|
1143
1137
|
o = o.uniq.compact if o.respond_to?(:uniq)
|
@@ -1146,7 +1140,6 @@ module Bud
|
|
1146
1140
|
o.each{|i| @to_delete_by_key << prep_tuple(i)}
|
1147
1141
|
end
|
1148
1142
|
end
|
1149
|
-
o
|
1150
1143
|
end
|
1151
1144
|
|
1152
1145
|
public
|