bud 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README +2 -3
- data/bin/budvis +0 -66
- data/docs/README.md +27 -15
- data/docs/bust.md +1 -1
- data/docs/cheat.md +79 -30
- data/docs/operational.md +8 -4
- data/examples/basics/paths.rb +5 -3
- data/lib/bud/aggs.rb +1 -1
- data/lib/bud/bud_meta.rb +11 -2
- data/lib/bud/bust/bust.rb +1 -1
- data/lib/bud/collections.rb +78 -20
- data/lib/bud/deploy/threaddeploy.rb +1 -1
- data/lib/bud/errors.rb +3 -0
- data/lib/bud/graphs.rb +25 -26
- data/lib/bud/joins.rb +78 -33
- data/lib/bud/metrics.rb +43 -0
- data/lib/bud/monkeypatch.rb +1 -1
- data/lib/bud/rebl.rb +20 -13
- data/lib/bud/rewrite.rb +217 -39
- data/lib/bud/server.rb +16 -13
- data/lib/bud/state.rb +39 -25
- data/lib/bud/storage/dbm.rb +6 -1
- data/lib/bud/storage/tokyocabinet.rb +6 -0
- data/lib/bud/storage/zookeeper.rb +6 -6
- data/lib/bud/viz.rb +5 -1
- data/lib/bud/viz_util.rb +70 -0
- data/lib/bud.rb +227 -99
- metadata +33 -24
- data/docs/c.html +0 -251
- data/examples/deploy/deploy_ip_port +0 -1
- data/examples/deploy/keys.rb +0 -5
- data/lib/bud.rb.orig +0 -806
data/lib/bud/rewrite.rb
CHANGED
@@ -8,11 +8,11 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
8
8
|
@bud_instance = bud_instance
|
9
9
|
@ops = {:<< => 1, :< => 1, :<= => 1}
|
10
10
|
@monotonic_whitelist = {
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
+
:schema => 1, :keys => 1, :values => 1, :payloads => 1, :~ => 1
|
15
|
+
}
|
16
16
|
@temp_ops = {:-@ => 1, :~ => 1, :+@ => 1}
|
17
17
|
@tables = {}
|
18
18
|
@nm = false
|
@@ -115,7 +115,9 @@ class RuleRewriter < Ruby2Ruby # :nodoc: all
|
|
115
115
|
drain(exp)
|
116
116
|
end
|
117
117
|
|
118
|
-
#
|
118
|
+
# We want to rewrite "map" calls on BudCollections to "pro" calls. It is hard
|
119
|
+
# to do this accurately (issue #225), so we just replace map calls liberally
|
120
|
+
# and define Enumerable#pro as an alias for "map".
|
119
121
|
def map2pro(exp)
|
120
122
|
if exp[1] and exp[1][0] and exp[1][0] == :iter \
|
121
123
|
and exp[1][1] and exp[1][1][1] and exp[1][1][1][0] == :call
|
@@ -152,10 +154,11 @@ class AttrNameRewriter < SexpProcessor # :nodoc: all
|
|
152
154
|
if exp[2] and exp[2][0] == :lasgn and @collnames.size == 1 #single-table iter
|
153
155
|
raise Bud::CompileError, "nested redefinition of block variable \"#{exp[2][1]}\" not allowed" if @iterhash[exp[2][1]]
|
154
156
|
@iterhash[exp[2][1]] = @collnames[0]
|
155
|
-
elsif exp[2] and exp[2][0] == :lasgn and @collnames.size > 1 # join iter with lefts/rights
|
156
|
-
|
157
|
+
elsif exp[2] and exp[2][0] == :lasgn and @collnames.size > 1 and exp[1] # join iter with lefts/rights
|
158
|
+
case exp[1][2]
|
159
|
+
when :lefts
|
157
160
|
@iterhash[exp[2][1]] = @collnames[0]
|
158
|
-
|
161
|
+
when :rights
|
159
162
|
@iterhash[exp[2][1]] = @collnames[1]
|
160
163
|
else
|
161
164
|
raise Bud::CompileError, "nested redefinition of block variable \"#{exp[2][1]}\" not allowed" if @iterhash[exp[2][1]]
|
@@ -315,6 +318,7 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
315
318
|
super()
|
316
319
|
self.require_empty = false
|
317
320
|
self.expected = Sexp
|
321
|
+
@keyword = :temp
|
318
322
|
|
319
323
|
@tmp_tables = []
|
320
324
|
@did_work = false
|
@@ -322,7 +326,6 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
322
326
|
|
323
327
|
def process_defn(exp)
|
324
328
|
tag, name, args, scope = exp
|
325
|
-
|
326
329
|
if name.to_s =~ /^__bloom__.+/
|
327
330
|
block = scope[1]
|
328
331
|
|
@@ -337,35 +340,41 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
337
340
|
# correct the misparsing.
|
338
341
|
if n.sexp_type == :iter
|
339
342
|
iter_body = n.sexp_body
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
_, recv, meth, meth_args = call_node
|
345
|
-
if meth == :temp and recv.nil?
|
346
|
-
_, lhs, op, rhs = meth_args.sexp_body.first
|
347
|
-
|
348
|
-
old_rhs_body = rhs.sexp_body
|
349
|
-
rhs[1] = s(:iter)
|
350
|
-
rhs[1] += old_rhs_body
|
351
|
-
rhs[1] += iter_body[1..-1]
|
352
|
-
block[i] = n = call_node
|
353
|
-
@did_work = true
|
354
|
-
end
|
343
|
+
new_n = fix_temp_decl(iter_body)
|
344
|
+
unless new_n.nil?
|
345
|
+
block[i] = n = new_n
|
346
|
+
@did_work = true
|
355
347
|
end
|
356
348
|
end
|
357
349
|
|
358
350
|
_, recv, meth, meth_args = n
|
359
|
-
if meth ==
|
360
|
-
block[i] =
|
351
|
+
if meth == @keyword and recv.nil?
|
352
|
+
block[i] = rewrite_me(n)
|
361
353
|
@did_work = true
|
362
354
|
end
|
363
355
|
end
|
364
356
|
end
|
365
|
-
|
366
357
|
s(tag, name, args, scope)
|
367
358
|
end
|
368
359
|
|
360
|
+
def fix_temp_decl(iter_body)
|
361
|
+
if iter_body.first.sexp_type == :call
|
362
|
+
call_node = iter_body.first
|
363
|
+
|
364
|
+
_, recv, meth, meth_args = call_node
|
365
|
+
if meth == @keyword and recv.nil?
|
366
|
+
_, lhs, op, rhs = meth_args.sexp_body.first
|
367
|
+
|
368
|
+
old_rhs_body = rhs.sexp_body
|
369
|
+
rhs[1] = s(:iter)
|
370
|
+
rhs[1] += old_rhs_body
|
371
|
+
rhs[1] += iter_body[1..-1]
|
372
|
+
return call_node
|
373
|
+
end
|
374
|
+
end
|
375
|
+
return nil
|
376
|
+
end
|
377
|
+
|
369
378
|
def get_state_meth(klass)
|
370
379
|
return if @tmp_tables.empty?
|
371
380
|
block = s(:block)
|
@@ -375,12 +384,12 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
375
384
|
block << s(:call, nil, :temp, args)
|
376
385
|
end
|
377
386
|
|
378
|
-
meth_name = Module.make_state_meth_name(klass).to_s + "
|
387
|
+
meth_name = Module.make_state_meth_name(klass).to_s + "__" + @keyword.to_s
|
379
388
|
return s(:defn, meth_name.to_sym, s(:args), s(:scope, block))
|
380
389
|
end
|
381
390
|
|
382
391
|
private
|
383
|
-
def
|
392
|
+
def rewrite_me(exp)
|
384
393
|
_, recv, meth, args = exp
|
385
394
|
|
386
395
|
raise Bud::CompileError unless recv == nil
|
@@ -397,6 +406,107 @@ class TempExpander < SexpProcessor # :nodoc: all
|
|
397
406
|
end
|
398
407
|
end
|
399
408
|
|
409
|
+
# We do four things here for each "with" block
|
410
|
+
# 1) Remove it from the AST
|
411
|
+
# 2) Use rewrite_me in the parent class to get the collection name pushed onto @tmp_tables.
|
412
|
+
# 3) Extract the definition of the "with" collection and push it onto @with_defns
|
413
|
+
# 4) Extract the rules in the body of the "with" block and push it onto @with_rules
|
414
|
+
|
415
|
+
class WithExpander < TempExpander
|
416
|
+
attr_reader :with_rules, :with_defns
|
417
|
+
def initialize
|
418
|
+
super()
|
419
|
+
@keyword = :with
|
420
|
+
@with_rules = []
|
421
|
+
@with_defns = []
|
422
|
+
end
|
423
|
+
|
424
|
+
def process_defn(exp)
|
425
|
+
tag, name, args, scope = exp
|
426
|
+
if name.to_s =~ /^__bloom__.+/
|
427
|
+
block = scope[1]
|
428
|
+
|
429
|
+
block.each_with_index do |n,i|
|
430
|
+
if i == 0
|
431
|
+
raise Bud::CompileError if n != :block
|
432
|
+
next
|
433
|
+
end
|
434
|
+
|
435
|
+
# temp declarations are misparsed if the RHS contains certain constructs
|
436
|
+
# (e.g., group, "do |f| ... end" rather than "{|f| ... }"). Rewrite to
|
437
|
+
# correct the misparsing.
|
438
|
+
if n.sexp_type == :iter
|
439
|
+
block[i] = nil
|
440
|
+
iter_body = n.sexp_body
|
441
|
+
n = fix_temp_decl(iter_body)
|
442
|
+
@with_defns.push n
|
443
|
+
@did_work = true unless n.nil?
|
444
|
+
end
|
445
|
+
|
446
|
+
_, recv, meth, meth_args = n
|
447
|
+
if meth == @keyword and recv.nil?
|
448
|
+
block[i] = nil
|
449
|
+
n = rewrite_me(n)
|
450
|
+
@with_defns.push n
|
451
|
+
@did_work = true unless n.nil?
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
block.compact! unless block.nil? # remove the nils that got pulled out
|
456
|
+
|
457
|
+
return s(tag, name, args, scope)
|
458
|
+
end
|
459
|
+
|
460
|
+
def get_state_meth(klass)
|
461
|
+
return if @tmp_tables.empty?
|
462
|
+
block = s(:block)
|
463
|
+
|
464
|
+
t = @tmp_tables.pop
|
465
|
+
args = s(:arglist, s(:lit, t.to_sym))
|
466
|
+
block << s(:call, nil, :temp, args)
|
467
|
+
|
468
|
+
meth_name = Module.make_state_meth_name(klass).to_s + "__" + @keyword.to_s
|
469
|
+
return s(:defn, meth_name.to_sym, s(:args), s(:scope, block))
|
470
|
+
end
|
471
|
+
|
472
|
+
private
|
473
|
+
def rewrite_me(exp)
|
474
|
+
_, recv, meth, args = exp
|
475
|
+
|
476
|
+
raise Bud::CompileError unless recv == nil
|
477
|
+
nest_call = args.sexp_body.first
|
478
|
+
raise Bud::CompileError unless nest_call.sexp_type == :call
|
479
|
+
|
480
|
+
nest_recv, nest_op, nest_args = nest_call.sexp_body
|
481
|
+
raise Bud::CompileError unless nest_recv.sexp_type == :lit
|
482
|
+
|
483
|
+
tmp_name = nest_recv.sexp_body.first
|
484
|
+
@tmp_tables.push tmp_name
|
485
|
+
nest_block = args.sexp_body[1]
|
486
|
+
if nest_block.first == :call
|
487
|
+
# a one-rule block doesn't get wrapped in a block. wrap it ourselves.
|
488
|
+
nest_block = s(:block, nest_block)
|
489
|
+
end
|
490
|
+
@with_rules.push nest_block
|
491
|
+
new_recv = s(:call, nil, tmp_name, s(:arglist))
|
492
|
+
return s(:call, new_recv, nest_op, nest_args)
|
493
|
+
end
|
494
|
+
|
495
|
+
undef get_state_meth
|
496
|
+
|
497
|
+
public
|
498
|
+
def get_state_meth(klass)
|
499
|
+
return if @tmp_tables.empty?
|
500
|
+
block = s(:block)
|
501
|
+
|
502
|
+
args = s(:arglist, s(:lit, @tmp_tables.pop.to_sym))
|
503
|
+
block << s(:call, nil, :temp, args)
|
504
|
+
|
505
|
+
meth_name = Module.make_state_meth_name(klass).to_s + "__" + @keyword.to_s
|
506
|
+
return s(:defn, meth_name.to_sym, s(:args), s(:scope, block))
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
400
510
|
class DefnRenamer < SexpProcessor # :nodoc: all
|
401
511
|
def initialize(local_name, rename_tbl)
|
402
512
|
super()
|
@@ -448,10 +558,24 @@ module ModuleRewriter # :nodoc: all
|
|
448
558
|
# the import site. Note that additional rewrites are needed to ensure that
|
449
559
|
# code in the import site that accesses module contents does the right thing;
|
450
560
|
# see Bud#rewrite_local_methods.
|
561
|
+
|
562
|
+
@@with_id = 0 # upon initialize
|
563
|
+
def self.with_id
|
564
|
+
@@with_id
|
565
|
+
end
|
566
|
+
|
567
|
+
def self.incr_with_id
|
568
|
+
@@with_id += 1
|
569
|
+
end
|
570
|
+
|
451
571
|
def self.do_import(import_site, mod, local_name)
|
452
|
-
|
572
|
+
# ast_process_withs modifies its argument as a side-effect
|
573
|
+
# and returns a matching ast.
|
574
|
+
# hence we run it before the other rewrites.
|
575
|
+
ast = ast_process_withs(mod)
|
453
576
|
ast = ast_flatten_nested_refs(ast, mod.bud_import_table)
|
454
577
|
ast = ast_process_temps(ast, mod)
|
578
|
+
|
455
579
|
ast, new_mod_name = ast_rename_module(ast, import_site, mod, local_name)
|
456
580
|
rename_tbl = {}
|
457
581
|
ast = ast_rename_methods(ast, local_name, rename_tbl)
|
@@ -461,7 +585,6 @@ module ModuleRewriter # :nodoc: all
|
|
461
585
|
str = Ruby2Ruby.new.process(ast)
|
462
586
|
rv = import_site.module_eval str
|
463
587
|
raise Bud::BudError unless rv.nil?
|
464
|
-
|
465
588
|
return new_mod_name
|
466
589
|
end
|
467
590
|
|
@@ -486,15 +609,16 @@ module ModuleRewriter # :nodoc: all
|
|
486
609
|
def self.get_raw_parse_tree(klass)
|
487
610
|
pt = RawParseTree.new(false)
|
488
611
|
klassname = klass.name
|
612
|
+
klassname = klass.to_s if klassname.empty? #("anon_" + Process.pid.to_s + "_" + klass.object_id.to_s) if klassname.empty
|
489
613
|
klassname = klassname.to_sym
|
490
614
|
|
491
615
|
code = if Class === klass then
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
616
|
+
sc = klass.superclass
|
617
|
+
sc_name = ((sc.nil? or sc.name.empty?) ? "nil" : sc.name).intern
|
618
|
+
[:class, klassname, [:const, sc_name]]
|
619
|
+
else
|
620
|
+
[:module, klassname]
|
621
|
+
end
|
498
622
|
|
499
623
|
method_names = klass.private_instance_methods false
|
500
624
|
# protected methods are included in instance_methods, go figure!
|
@@ -542,9 +666,63 @@ module ModuleRewriter # :nodoc: all
|
|
542
666
|
# Insert the new extra state method into the module's AST
|
543
667
|
ast << new_meth
|
544
668
|
end
|
545
|
-
|
546
669
|
return ast
|
547
670
|
end
|
671
|
+
|
672
|
+
def self.ast_mangle_with(w,klass)
|
673
|
+
r2r = Ruby2Ruby.new
|
674
|
+
|
675
|
+
while st = w.get_state_meth(klass)
|
676
|
+
# generate the module
|
677
|
+
tmpmod = Module.new
|
678
|
+
|
679
|
+
# add a state block to define a temp for the collection name
|
680
|
+
state_src = r2r.process(st)
|
681
|
+
tmpmod.module_eval(state_src)
|
682
|
+
|
683
|
+
# add a bloom block
|
684
|
+
bloom_blk = s(:defn, :__bloom__rules, s(:args), s(:scope, s(:block)))
|
685
|
+
inblk = bloom_blk[3][1]
|
686
|
+
|
687
|
+
# add in the rule that was in the "with" definition
|
688
|
+
newdefn = w.with_defns.pop
|
689
|
+
inblk << newdefn unless newdefn.nil?
|
690
|
+
|
691
|
+
# add in all the rules from the body of the "with" block
|
692
|
+
newrules = w.with_rules.pop
|
693
|
+
newrules.each_with_index do |ast, i|
|
694
|
+
inblk << ast unless i == 0
|
695
|
+
end
|
696
|
+
bloom_src = r2r.process(bloom_blk)
|
697
|
+
|
698
|
+
# eval all that Ruby we generated and import new Module into our code
|
699
|
+
tmpmod.module_eval(bloom_src)
|
700
|
+
modname = "with__"+ModuleRewriter.with_id.to_s
|
701
|
+
klass.import tmpmod => modname.to_sym
|
702
|
+
|
703
|
+
ModuleRewriter.incr_with_id
|
704
|
+
end
|
705
|
+
end
|
706
|
+
|
707
|
+
def self.ast_process_withs(mod)
|
708
|
+
# strategy to handle withs:
|
709
|
+
# 1) run WithExpander#process to delete the "with" blocks and extract their contents
|
710
|
+
# 2) get the state and rules mangled appropriately into modules
|
711
|
+
# 3) run mod.import on each
|
712
|
+
# 4) call self.get_raw_parse_tree on the result to generate an AST
|
713
|
+
|
714
|
+
ast = get_module_ast(mod)
|
715
|
+
w = WithExpander.new
|
716
|
+
ast = w.process(ast)
|
717
|
+
mod_s, name_s, blocks = ast[0], ast[1], ast[2..-1]
|
718
|
+
tag, name, args, scope = blocks[0]
|
719
|
+
|
720
|
+
self.ast_mangle_with(w,mod)
|
721
|
+
|
722
|
+
retval = Unifier.new.process(self.get_raw_parse_tree(mod))
|
723
|
+
return retval
|
724
|
+
# return s(mod_s, name_s, *blocks)
|
725
|
+
end
|
548
726
|
|
549
727
|
# Rename the given module's name to be a mangle of import site, imported
|
550
728
|
# module, and local bind name. We also rename all the instance methods defined
|
data/lib/bud/server.rb
CHANGED
@@ -17,28 +17,31 @@ module Bud
|
|
17
17
|
message_received(obj)
|
18
18
|
end
|
19
19
|
|
20
|
+
begin
|
21
|
+
@bud.tick_internal if @bud.running_async
|
22
|
+
rescue Exception
|
23
|
+
# If we raise an exception here, EM dies, which causes problems (e.g.,
|
24
|
+
# other Bud instances in the same process will crash). Ignoring the
|
25
|
+
# error isn't best though -- we should do better (#74).
|
26
|
+
puts "Exception handling network messages: #{$!}"
|
27
|
+
puts "Inbound messages:"
|
28
|
+
@bud.inbound.each do |m|
|
29
|
+
puts " #{m[1].inspect} (channel: #{m[0]})"
|
30
|
+
end
|
31
|
+
@bud.inbound.clear
|
32
|
+
end
|
33
|
+
|
20
34
|
@bud.rtracer.sleep if @bud.options[:rtrace]
|
21
35
|
end
|
22
36
|
|
23
37
|
def message_received(obj)
|
24
|
-
|
25
|
-
|
26
|
-
@bud.tables[obj[0].to_sym].nil? and obj[1].class <= Array)
|
38
|
+
unless (obj.class <= Array and obj.length == 2 and
|
39
|
+
@bud.tables.include?(obj[0].to_sym) and obj[1].class <= Array)
|
27
40
|
raise BudError, "Bad inbound message of class #{obj.class}: #{obj.inspect}"
|
28
41
|
end
|
29
42
|
|
30
43
|
@bud.rtracer.recv(obj) if @bud.options[:rtrace]
|
31
|
-
|
32
44
|
@bud.inbound << obj
|
33
|
-
begin
|
34
|
-
@bud.tick unless @bud.lazy
|
35
|
-
rescue Exception
|
36
|
-
# If we raise an exception here, EM dies, which causes problems (e.g.,
|
37
|
-
# other Bud instances in the same process will crash). Ignoring the
|
38
|
-
# error isn't best though -- we should do better (#74).
|
39
|
-
puts "Exception handling network message (channel '#{obj[0]}'): #{$!}"
|
40
|
-
puts caller.join("\n")
|
41
|
-
end
|
42
45
|
end
|
43
46
|
end
|
44
47
|
end
|
data/lib/bud/state.rb
CHANGED
@@ -21,7 +21,7 @@ module Bud
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
public
|
26
26
|
|
27
27
|
def input # :nodoc: all
|
@@ -38,17 +38,52 @@ module Bud
|
|
38
38
|
scratch(name, schema)
|
39
39
|
end
|
40
40
|
|
41
|
-
# declare
|
41
|
+
# declare an in-memory, non-transient collection. default schema <tt>[:key] => [:val]</tt>.
|
42
42
|
def table(name, schema=nil)
|
43
43
|
define_collection(name)
|
44
44
|
@tables[name] = Bud::BudTable.new(name, self, schema)
|
45
45
|
end
|
46
|
+
|
47
|
+
# declare a syncronously-flushed persistent collection. default schema <tt>[:key] => [:val]</tt>.
|
48
|
+
def sync(name, storage, schema=nil)
|
49
|
+
define_collection(name)
|
50
|
+
case storage
|
51
|
+
when :dbm
|
52
|
+
@tables[name] = Bud::BudDbmTable.new(name, self, schema)
|
53
|
+
@dbm_tables[name] = @tables[name]
|
54
|
+
when :tokyo
|
55
|
+
@tables[name] = Bud::BudTcTable.new(name, self, schema)
|
56
|
+
@tc_tables[name] = @tables[name]
|
57
|
+
else
|
58
|
+
raise BudError, "Unknown synchronous storage engine #{storage.to_s}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def store(name, storage, schema=nil)
|
63
|
+
define_collection(name)
|
64
|
+
case storage
|
65
|
+
when :zookeeper
|
66
|
+
# treat "schema" as a hash of options
|
67
|
+
options = schema
|
68
|
+
raise BudError, "Zookeeper tables require a :path option" if options[:path].nil?
|
69
|
+
options[:addr] ||= "localhost:2181"
|
70
|
+
@tables[name] = Bud::BudZkTable.new(name, options[:path], options[:addr], self)
|
71
|
+
@zk_tables[name] = @tables[name]
|
72
|
+
else
|
73
|
+
raise BudError, "Unknown async storage engine #{storage.to_s}"
|
74
|
+
end
|
75
|
+
end
|
46
76
|
|
47
77
|
# declare a transient collection. default schema <tt>[:key] => [:val]</tt>
|
48
78
|
def scratch(name, schema=nil)
|
49
79
|
define_collection(name)
|
50
80
|
@tables[name] = Bud::BudScratch.new(name, self, schema)
|
51
81
|
end
|
82
|
+
|
83
|
+
def readonly(name, schema=nil)
|
84
|
+
define_collection(name)
|
85
|
+
@tables[name] = Bud::BudReadOnly.new(name, self, schema)
|
86
|
+
end
|
52
87
|
|
53
88
|
# declare a scratch in a bloom statement lhs. schema inferred from rhs.
|
54
89
|
def temp(name)
|
@@ -56,7 +91,7 @@ module Bud
|
|
56
91
|
# defer schema definition until merge
|
57
92
|
@tables[name] = Bud::BudTemp.new(name, self, nil, true)
|
58
93
|
end
|
59
|
-
|
94
|
+
|
60
95
|
# declare a transient network collection. default schema <tt>[:address, :val] => []</tt>
|
61
96
|
def channel(name, schema=nil, loopback=false)
|
62
97
|
define_collection(name)
|
@@ -84,7 +119,7 @@ module Bud
|
|
84
119
|
def periodic(name, period=1)
|
85
120
|
define_collection(name)
|
86
121
|
raise BudError if @periodics.has_key? [name]
|
87
|
-
@periodics << [name,
|
122
|
+
@periodics << [name, period]
|
88
123
|
@tables[name] = Bud::BudPeriodic.new(name, self)
|
89
124
|
end
|
90
125
|
|
@@ -98,25 +133,4 @@ module Bud
|
|
98
133
|
@tables[name] = Bud::BudTerminal.new(name, [:line], self)
|
99
134
|
@channels[name] = @tables[name]
|
100
135
|
end
|
101
|
-
|
102
|
-
# declare a TokyoCabinet table
|
103
|
-
def tctable(name, schema=nil)
|
104
|
-
define_collection(name)
|
105
|
-
@tables[name] = Bud::BudTcTable.new(name, self, schema)
|
106
|
-
@tc_tables[name] = @tables[name]
|
107
|
-
end
|
108
|
-
|
109
|
-
# declare a dbm table
|
110
|
-
def dbm_table(name, schema=nil)
|
111
|
-
define_collection(name)
|
112
|
-
@tables[name] = Bud::BudDbmTable.new(name, self, schema)
|
113
|
-
@dbm_tables[name] = @tables[name]
|
114
|
-
end
|
115
|
-
|
116
|
-
# declare an Apache ZooKeeper table
|
117
|
-
def zktable(name, path, addr="localhost:2181")
|
118
|
-
define_collection(name)
|
119
|
-
@tables[name] = Bud::BudZkTable.new(name, path, addr, self)
|
120
|
-
@zk_tables[name] = @tables[name]
|
121
|
-
end
|
122
136
|
end
|
data/lib/bud/storage/dbm.rb
CHANGED
@@ -6,11 +6,14 @@ module Bud
|
|
6
6
|
def initialize(name, bud_instance, given_schema)
|
7
7
|
dbm_dir = bud_instance.options[:dbm_dir]
|
8
8
|
raise BudError, "dbm support must be enabled via 'dbm_dir'" unless dbm_dir
|
9
|
+
if bud_instance.port.nil?
|
10
|
+
raise BudError, "use of dbm storage requires an explicit port to be specified in Bud initialization options"
|
11
|
+
end
|
12
|
+
|
9
13
|
unless File.exists?(dbm_dir)
|
10
14
|
Dir.mkdir(dbm_dir)
|
11
15
|
puts "Created directory: #{dbm_dir}" unless bud_instance.options[:quiet]
|
12
16
|
end
|
13
|
-
|
14
17
|
dirname = "#{dbm_dir}/bud_#{bud_instance.port}"
|
15
18
|
unless File.exists?(dirname)
|
16
19
|
Dir.mkdir(dirname)
|
@@ -81,6 +84,7 @@ module Bud
|
|
81
84
|
each_storage(&block)
|
82
85
|
else
|
83
86
|
b.each_value do |v|
|
87
|
+
tick_metrics if bud_instance.options[:metrics]
|
84
88
|
yield v
|
85
89
|
end
|
86
90
|
end
|
@@ -91,6 +95,7 @@ module Bud
|
|
91
95
|
@dbm.each do |k,v|
|
92
96
|
k_ary = MessagePack.unpack(k)
|
93
97
|
v_ary = MessagePack.unpack(v)
|
98
|
+
tick_metrics if bud_instance.options[:metrics]
|
94
99
|
yield make_tuple(k_ary, v_ary)
|
95
100
|
end
|
96
101
|
end
|
@@ -10,6 +10,10 @@ module Bud
|
|
10
10
|
def initialize(name, bud_instance, given_schema)
|
11
11
|
tc_dir = bud_instance.options[:tc_dir]
|
12
12
|
raise BudError, "TC support must be enabled via 'tc_dir'" unless tc_dir
|
13
|
+
if bud_instance.port.nil?
|
14
|
+
raise BudError, "use of dbm storage requires an explicit port to be specified in Bud initialization options"
|
15
|
+
end
|
16
|
+
|
13
17
|
unless File.exists?(tc_dir)
|
14
18
|
Dir.mkdir(tc_dir)
|
15
19
|
puts "Created directory: #{tc_dir}" unless bud_instance.options[:quiet]
|
@@ -86,6 +90,7 @@ module Bud
|
|
86
90
|
each_storage(&block)
|
87
91
|
else
|
88
92
|
b.each_value do |v|
|
93
|
+
tick_metrics if bud_instance.options[:metrics]
|
89
94
|
yield v
|
90
95
|
end
|
91
96
|
end
|
@@ -96,6 +101,7 @@ module Bud
|
|
96
101
|
@hdb.each do |k,v|
|
97
102
|
k_ary = MessagePack.unpack(k)
|
98
103
|
v_ary = MessagePack.unpack(v)
|
104
|
+
tick_metrics if bud_instance.options[:metrics]
|
99
105
|
yield make_tuple(k_ary, v_ary)
|
100
106
|
end
|
101
107
|
end
|
@@ -9,7 +9,7 @@ module Bud
|
|
9
9
|
class BudZkTable < BudCollection # :nodoc: all
|
10
10
|
def initialize(name, zk_path, zk_addr, bud_instance)
|
11
11
|
unless defined? HAVE_ZOOKEEPER
|
12
|
-
raise BudError, "zookeeper gem is not installed:
|
12
|
+
raise BudError, "zookeeper gem is not installed: zookeeper-backed stores cannot be used"
|
13
13
|
end
|
14
14
|
|
15
15
|
# schema = {[:key] => [:val]}
|
@@ -109,9 +109,9 @@ module Bud
|
|
109
109
|
}
|
110
110
|
|
111
111
|
# If we have new data, force a new Bud tick in the near future
|
112
|
-
if need_tick and
|
112
|
+
if need_tick and @bud_instance.running_async
|
113
113
|
EventMachine::schedule {
|
114
|
-
@bud_instance.
|
114
|
+
@bud_instance.tick_internal
|
115
115
|
}
|
116
116
|
end
|
117
117
|
end
|
@@ -164,15 +164,15 @@ module Bud
|
|
164
164
|
end
|
165
165
|
|
166
166
|
superator "<+" do |o|
|
167
|
-
raise BudError, "Illegal use of <+ with
|
167
|
+
raise BudError, "Illegal use of <+ with zookeeper store '#{@tabname}' on left"
|
168
168
|
end
|
169
169
|
|
170
170
|
def <=(o)
|
171
|
-
raise BudError, "Illegal use of <= with
|
171
|
+
raise BudError, "Illegal use of <= with zookeeper store '#{@tabname}' on left"
|
172
172
|
end
|
173
173
|
|
174
174
|
def <<(o)
|
175
|
-
raise BudError, "Illegal use of << with
|
175
|
+
raise BudError, "Illegal use of << with zookeeper store '#{@tabname}' on left"
|
176
176
|
end
|
177
177
|
end
|
178
178
|
end
|
data/lib/bud/viz.rb
CHANGED