bud 0.0.8 → 0.1.0.pre1
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/README +4 -10
- data/bin/budplot +1 -2
- data/docs/cheat.md +2 -15
- data/examples/basics/paths.rb +7 -7
- data/lib/bud/aggs.rb +15 -19
- data/lib/bud/bud_meta.rb +165 -77
- data/lib/bud/bust/bust.rb +11 -4
- data/lib/bud/collections.rb +643 -280
- data/lib/bud/depanalysis.rb +50 -25
- data/lib/bud/executor/elements.rb +592 -0
- data/lib/bud/executor/group.rb +104 -0
- data/lib/bud/executor/join.rb +638 -0
- data/lib/bud/graphs.rb +12 -11
- data/lib/bud/joins.rb +2 -1
- data/lib/bud/meta_algebra.rb +5 -4
- data/lib/bud/metrics.rb +9 -3
- data/lib/bud/monkeypatch.rb +131 -23
- data/lib/bud/rebl.rb +41 -28
- data/lib/bud/rewrite.rb +112 -440
- data/lib/bud/server.rb +3 -2
- data/lib/bud/source.rb +109 -0
- data/lib/bud/state.rb +16 -9
- data/lib/bud/storage/dbm.rb +62 -16
- data/lib/bud/storage/zookeeper.rb +2 -2
- data/lib/bud/viz.rb +8 -4
- data/lib/bud/viz_util.rb +10 -9
- data/lib/bud.rb +413 -199
- metadata +40 -55
- data/examples/deploy/tokenring-ec2.rb +0 -26
- data/examples/deploy/tokenring-fork.rb +0 -15
- data/examples/deploy/tokenring-thread.rb +0 -15
- data/examples/deploy/tokenring.rb +0 -47
- data/lib/bud/deploy/deployer.rb +0 -67
- data/lib/bud/deploy/ec2deploy.rb +0 -199
- data/lib/bud/deploy/forkdeploy.rb +0 -90
- data/lib/bud/deploy/threaddeploy.rb +0 -38
- data/lib/bud/storage/tokyocabinet.rb +0 -190
- data/lib/bud/stratify.rb +0 -85
data/lib/bud/source.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'ruby_parser'
|
3
|
+
require 'bud/errors'
|
4
|
+
|
5
|
+
module Source
|
6
|
+
$cached_file_info = Struct.new(:curr_file, :lines, :last_state_bloom_line).new
|
7
|
+
|
8
|
+
#Reads the block corresponding to the location (string of the form "file:line_num").
|
9
|
+
#Returns an ast for the block
|
10
|
+
def Source.read_block(location)
|
11
|
+
raise Bud::CompileError, "Source must be present in a file; cannot read interactive shell or eval block" if location.start_with? '('
|
12
|
+
location =~ /^(.*):(\d+)/
|
13
|
+
filename, num = $1, $2.to_i
|
14
|
+
raise Bud::Error, "Couldn't determine filename from backtrace" if filename.nil?
|
15
|
+
lines = cache(filename, num)
|
16
|
+
# Note: num is 1-based.
|
17
|
+
|
18
|
+
src_asts = [] # array of SrcAsts to be returned
|
19
|
+
ruby_parser = RubyParser.new
|
20
|
+
|
21
|
+
stmt = "" # collection of lines that form one complete ruby statement
|
22
|
+
endok = true #
|
23
|
+
ast = nil
|
24
|
+
lines[num .. -1].each do |l|
|
25
|
+
next if l =~ /^\s*#/
|
26
|
+
break if endok and l =~ /^\s*([}]|end)/
|
27
|
+
stmt += l + "\n"
|
28
|
+
begin
|
29
|
+
ast = ruby_parser.parse stmt
|
30
|
+
endok = true
|
31
|
+
rescue => ex
|
32
|
+
# puts "Syntax Error on #{l}: #{ex}"
|
33
|
+
endok = false
|
34
|
+
ast = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
ast
|
38
|
+
end
|
39
|
+
|
40
|
+
def Source.cache(filename, num) # returns array of lines
|
41
|
+
if $cached_file_info.curr_file == filename
|
42
|
+
retval = $cached_file_info.lines
|
43
|
+
if $cached_file_info.last_state_bloom_line == num
|
44
|
+
# have no use for the cached info any more. reset it.
|
45
|
+
$cached_file_info.lines = []
|
46
|
+
$cached_file_info.curr_file = ""
|
47
|
+
$cached_file_info.last_state_bloom_line = -1
|
48
|
+
end
|
49
|
+
else
|
50
|
+
$cached_file_info.last_state_bloom_line = -1
|
51
|
+
$cached_file_info.curr_file = filename
|
52
|
+
$cached_file_info.lines = []
|
53
|
+
retval = []
|
54
|
+
File.open(filename, "r").each_with_index {|line, i|
|
55
|
+
retval << line
|
56
|
+
if line =~ /^ *(bloom|state)/
|
57
|
+
$cached_file_info.last_state_bloom_line = i
|
58
|
+
end
|
59
|
+
}
|
60
|
+
$cached_file_info.lines = retval
|
61
|
+
end
|
62
|
+
retval # array of lines.
|
63
|
+
end
|
64
|
+
|
65
|
+
# Tok is string tokenizer that extracts a substring matching the
|
66
|
+
# supplied regex, and internally advances past the matched substring.
|
67
|
+
# Leading white space is ignored.
|
68
|
+
# tok = Tok.new("foo 123")
|
69
|
+
# x = tok =~ /\w+/ # => x == 'foo'
|
70
|
+
# y = tok =~ /\d+/ # => y = '123'
|
71
|
+
class Tok
|
72
|
+
attr_accessor :str, :group
|
73
|
+
def initialize(str)
|
74
|
+
@str = str
|
75
|
+
@group = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
# match regex at beginning of string, and advance. Return matched token
|
79
|
+
def =~(regex)
|
80
|
+
s = @str
|
81
|
+
skiplen = 0
|
82
|
+
if s =~ /^\s*/
|
83
|
+
skiplen = $&.length
|
84
|
+
s = s[skiplen .. -1]
|
85
|
+
end
|
86
|
+
if (s =~ regex) == 0
|
87
|
+
# Regexp.last_match is local to this thread and method; squirrel
|
88
|
+
# it away for use in tok.[]
|
89
|
+
@group = Regexp.last_match
|
90
|
+
skiplen += $&.length
|
91
|
+
@str = @str[skiplen .. -1]
|
92
|
+
return $&
|
93
|
+
else
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# get the nth subgroup match
|
99
|
+
# t = Tok.new("a1122b"); t =~ /a(1+)(2+)b/ ; #=> t[0] = a1122b; t[1] = 11; t[2] = 22
|
100
|
+
def [](n)
|
101
|
+
@group ? @group[n] : nil
|
102
|
+
end
|
103
|
+
def pushBack(str)
|
104
|
+
@str = str + @str
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_s; @str; end
|
108
|
+
end
|
109
|
+
end
|
data/lib/bud/state.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
module Bud
|
2
2
|
######## methods for registering collection types
|
3
|
-
private
|
4
3
|
def define_collection(name)
|
5
4
|
if @tables.has_key? name
|
6
5
|
raise Bud::CompileError, "collection already exists: #{name}"
|
@@ -21,8 +20,6 @@ module Bud
|
|
21
20
|
end
|
22
21
|
end
|
23
22
|
|
24
|
-
public
|
25
|
-
|
26
23
|
def input # :nodoc: all
|
27
24
|
true
|
28
25
|
end
|
@@ -33,8 +30,9 @@ module Bud
|
|
33
30
|
|
34
31
|
# declare a transient collection to be an input or output interface
|
35
32
|
def interface(mode, name, schema=nil)
|
33
|
+
define_collection(name)
|
36
34
|
t_provides << [name.to_s, mode]
|
37
|
-
|
35
|
+
@tables[name] = (mode ? Bud::BudInputInterface : BudOutputInterface).new(name, self, schema)
|
38
36
|
end
|
39
37
|
|
40
38
|
# declare an in-memory, non-transient collection. default schema <tt>[:key] => [:val]</tt>.
|
@@ -43,16 +41,19 @@ module Bud
|
|
43
41
|
@tables[name] = Bud::BudTable.new(name, self, schema)
|
44
42
|
end
|
45
43
|
|
46
|
-
# declare a
|
44
|
+
# declare a collection-generating expression. default schema <tt>[:key] => [:val]</tt>.
|
45
|
+
def coll_expr(name, expr, schema=nil)
|
46
|
+
define_collection(name)
|
47
|
+
@tables[name] = Bud::BudCollExpr.new(name, self, expr, schema)
|
48
|
+
end
|
49
|
+
|
50
|
+
# declare a syncronously-flushed persistent collection. default schema <tt>[:key] => [:val]</tt>.
|
47
51
|
def sync(name, storage, schema=nil)
|
48
52
|
define_collection(name)
|
49
53
|
case storage
|
50
54
|
when :dbm
|
51
55
|
@tables[name] = Bud::BudDbmTable.new(name, self, schema)
|
52
56
|
@dbm_tables[name] = @tables[name]
|
53
|
-
when :tokyo
|
54
|
-
@tables[name] = Bud::BudTcTable.new(name, self, schema)
|
55
|
-
@tc_tables[name] = @tables[name]
|
56
57
|
else
|
57
58
|
raise Bud::Error, "unknown synchronous storage engine #{storage.to_s}"
|
58
59
|
end
|
@@ -84,6 +85,12 @@ module Bud
|
|
84
85
|
@tables[name] = Bud::BudReadOnly.new(name, self, schema)
|
85
86
|
end
|
86
87
|
|
88
|
+
def signal(name, schema=nil)
|
89
|
+
define_collection(name)
|
90
|
+
@tables[name] = Bud::BudSignal.new(name, self, schema)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
87
94
|
# declare a scratch in a bloom statement lhs. schema inferred from rhs.
|
88
95
|
def temp(name)
|
89
96
|
define_collection(name)
|
@@ -97,7 +104,7 @@ module Bud
|
|
97
104
|
@tables[name] = Bud::BudChannel.new(name, self, schema, loopback)
|
98
105
|
@channels[name] = @tables[name]
|
99
106
|
end
|
100
|
-
|
107
|
+
|
101
108
|
# declare a transient network collection that delivers facts back to the
|
102
109
|
# current Bud instance. This is syntax sugar for a channel that always
|
103
110
|
# delivers to the IP/port of the current Bud instance. Default schema
|
data/lib/bud/storage/dbm.rb
CHANGED
@@ -2,8 +2,9 @@ require 'dbm'
|
|
2
2
|
|
3
3
|
module Bud
|
4
4
|
# Persistent table implementation based on ndbm.
|
5
|
-
class BudDbmTable <
|
5
|
+
class BudDbmTable < BudPersistentCollection # :nodoc: all
|
6
6
|
def initialize(name, bud_instance, given_schema)
|
7
|
+
@invalidated = true
|
7
8
|
dbm_dir = bud_instance.options[:dbm_dir]
|
8
9
|
raise Bud::Error, "dbm support must be enabled via 'dbm_dir'" unless dbm_dir
|
9
10
|
if bud_instance.port.nil?
|
@@ -51,6 +52,10 @@ module Bud
|
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
55
|
+
def length
|
56
|
+
@dbm.length + @delta.length
|
57
|
+
end
|
58
|
+
|
54
59
|
def has_key?(k)
|
55
60
|
check_enumerable(k)
|
56
61
|
key_s = MessagePack.pack(k)
|
@@ -65,20 +70,25 @@ module Bud
|
|
65
70
|
end
|
66
71
|
|
67
72
|
def make_tuple(k_ary, v_ary)
|
68
|
-
t = Array.new(k_ary.length + v_ary.length)
|
73
|
+
#t = Array.new(k_ary.length + v_ary.length)
|
74
|
+
t = @struct.new
|
69
75
|
@key_colnums.each_with_index do |k,i|
|
70
76
|
t[k] = k_ary[i]
|
71
77
|
end
|
72
78
|
val_cols.each_with_index do |c,i|
|
73
79
|
t[cols.index(c)] = v_ary[i]
|
74
80
|
end
|
75
|
-
|
81
|
+
t
|
76
82
|
end
|
77
83
|
|
78
84
|
def each(&block)
|
79
85
|
each_from([@delta], &block)
|
80
86
|
each_storage(&block)
|
81
87
|
end
|
88
|
+
|
89
|
+
def each_raw(&block)
|
90
|
+
each_storage(&block)
|
91
|
+
end
|
82
92
|
|
83
93
|
def each_from(bufs, &block)
|
84
94
|
bufs.each do |b|
|
@@ -130,17 +140,45 @@ module Bud
|
|
130
140
|
|
131
141
|
# move deltas to on-disk storage, and new_deltas to deltas
|
132
142
|
def tick_deltas
|
133
|
-
|
134
|
-
|
143
|
+
unless @delta.empty?
|
144
|
+
merge_to_db(@delta)
|
145
|
+
@tick_delta += @delta.values
|
146
|
+
@delta.clear
|
147
|
+
end
|
148
|
+
unless @new_delta.empty?
|
149
|
+
@delta = @new_delta
|
150
|
+
@new_delta = {}
|
151
|
+
end
|
152
|
+
return !(@delta.empty?)
|
153
|
+
end
|
154
|
+
|
155
|
+
public
|
156
|
+
def flush_deltas
|
157
|
+
unless @delta.empty?
|
158
|
+
merge_to_db(@delta)
|
159
|
+
@tick_delta += @delta.values
|
160
|
+
@delta.clear
|
161
|
+
end
|
162
|
+
merge_to_db(@new_delta)
|
135
163
|
@new_delta = {}
|
136
164
|
end
|
137
165
|
|
166
|
+
# This is verbatim from BudTable. Need to DRY up. Should we be a subclass of BudTable?
|
167
|
+
public
|
168
|
+
def pending_delete(o)
|
169
|
+
if o.class <= Bud::PushElement
|
170
|
+
o.wire_to_delete self
|
171
|
+
elsif o.class <= Bud::BudCollection
|
172
|
+
o.pro.wire_to_delete self
|
173
|
+
else
|
174
|
+
@to_delete = @to_delete + o.map{|t| prep_tuple(t) unless t.nil?}
|
175
|
+
end
|
176
|
+
end
|
138
177
|
superator "<-" do |o|
|
139
|
-
o
|
140
|
-
@to_delete << tuple unless tuple.nil?
|
141
|
-
end
|
178
|
+
pending_delete(o)
|
142
179
|
end
|
143
|
-
|
180
|
+
|
181
|
+
|
144
182
|
def insert(tuple)
|
145
183
|
key = get_key_vals(tuple)
|
146
184
|
merge_tuple_to_db(key, tuple)
|
@@ -150,9 +188,7 @@ module Bud
|
|
150
188
|
|
151
189
|
# Remove to_delete and then add pending to db
|
152
190
|
def tick
|
153
|
-
|
154
|
-
raise Bud::Error, "orphaned tuples in @new_delta for #{@tabname}" unless @new_delta.empty?
|
155
|
-
|
191
|
+
deleted = nil
|
156
192
|
@to_delete.each do |tuple|
|
157
193
|
k = get_key_vals(tuple)
|
158
194
|
k_str = MessagePack.pack(k)
|
@@ -161,18 +197,28 @@ module Bud
|
|
161
197
|
db_cols = MessagePack.unpack(cols_str)
|
162
198
|
delete_cols = val_cols.map{|c| tuple[cols.index(c)]}
|
163
199
|
if db_cols == delete_cols
|
164
|
-
@dbm.delete k_str
|
200
|
+
deleted ||= @dbm.delete k_str
|
165
201
|
end
|
166
202
|
end
|
167
203
|
end
|
168
204
|
@to_delete = []
|
169
205
|
|
170
|
-
|
171
|
-
@pending
|
172
|
-
|
206
|
+
@invalidated = !deleted.nil?
|
207
|
+
unless @pending.empty?
|
208
|
+
@delta = @pending
|
209
|
+
# merge_to_db(@pending)
|
210
|
+
@pending = {}
|
211
|
+
end
|
173
212
|
flush
|
174
213
|
end
|
175
214
|
|
215
|
+
def invalidate_cache
|
216
|
+
end
|
217
|
+
|
218
|
+
def method_missing(sym, *args, &block)
|
219
|
+
@dbm.send sym, *args, &block
|
220
|
+
end
|
221
|
+
|
176
222
|
public
|
177
223
|
def length
|
178
224
|
@dbm.length
|
@@ -6,7 +6,7 @@ end
|
|
6
6
|
|
7
7
|
module Bud
|
8
8
|
# Persistent table implementation based on Zookeeper.
|
9
|
-
class BudZkTable <
|
9
|
+
class BudZkTable < BudPersistentCollection # :nodoc: all
|
10
10
|
def initialize(name, zk_path, zk_addr, bud_instance)
|
11
11
|
unless defined? HAVE_ZOOKEEPER
|
12
12
|
raise Bud::Error, "zookeeper gem is not installed: zookeeper-backed stores cannot be used"
|
@@ -94,7 +94,7 @@ module Bud
|
|
94
94
|
data = get_r[:data]
|
95
95
|
# XXX: For now, conflate empty string values with nil values
|
96
96
|
data ||= ""
|
97
|
-
new_children[c] =
|
97
|
+
new_children[c] = [c, data]
|
98
98
|
end
|
99
99
|
|
100
100
|
# We successfully fetched all the children of @zk_path; arrange to install
|
data/lib/bud/viz.rb
CHANGED
@@ -6,7 +6,6 @@ require 'bud/state'
|
|
6
6
|
class VizOnline #:nodoc: all
|
7
7
|
def initialize(bud_instance)
|
8
8
|
@bud_instance = bud_instance
|
9
|
-
return if bud_instance.class == Stratification or @bud_instance.class == DepAnalysis
|
10
9
|
@meta_tables = {'t_rules' => 1, 't_depends' => 1, 't_table_info' => 1, 't_cycle' => 1, 't_stratum' => 1, 't_depends_tc' => 1, 't_table_schema' => 1, 't_provides' => 1}
|
11
10
|
@bud_instance.options[:dbm_dir] = "DBM_#{@bud_instance.class}_#{bud_instance.options[:tag]}_#{bud_instance.object_id}_#{bud_instance.port}"
|
12
11
|
@table_info = bud_instance.tables[:t_table_info]
|
@@ -55,10 +54,16 @@ class VizOnline #:nodoc: all
|
|
55
54
|
collection.each do |row|
|
56
55
|
if collection.class == Hash
|
57
56
|
row = row[1]
|
58
|
-
|
59
|
-
if collection.class == Bud::BudPeriodic
|
57
|
+
elsif collection.class == Bud::BudPeriodic
|
60
58
|
row = row[0]
|
61
59
|
end
|
60
|
+
|
61
|
+
# bud.t_depends and t_rules have bud object in field[0]. Remove them since
|
62
|
+
# bud instances cannot/must not be serialized.
|
63
|
+
if row[0].class <= Bud
|
64
|
+
row = row.to_a if row.class != Array
|
65
|
+
row = row[1..-1] if row[0].class <= Bud
|
66
|
+
end
|
62
67
|
newrow = [tab, @bud_instance.budtime, row]
|
63
68
|
begin
|
64
69
|
@logtab << newrow
|
@@ -69,7 +74,6 @@ class VizOnline #:nodoc: all
|
|
69
74
|
end
|
70
75
|
|
71
76
|
def do_cards
|
72
|
-
return if @bud_instance.class == Stratification or @bud_instance.class == DepAnalysis
|
73
77
|
@bud_instance.tables.each do |t|
|
74
78
|
tab = t[0]
|
75
79
|
next if tab == "the_big_log"
|
data/lib/bud/viz_util.rb
CHANGED
@@ -80,9 +80,10 @@ module VizUtil #:nodoc: all
|
|
80
80
|
bit = bud_instance.builtin_tables
|
81
81
|
VizUtil.ma_tables.each_pair{|k, v| bit[k] = v}
|
82
82
|
|
83
|
-
|
83
|
+
depanalysis = bud_instance.meta_parser.depanalysis
|
84
|
+
write_graphs(tabinf, bit, depanalysis.cycle,
|
84
85
|
bud_instance.t_depends, bud_instance.t_rules, viz_name,
|
85
|
-
output_base, fmt, collapse,
|
86
|
+
output_base, fmt, collapse, depanalysis, -1, nil,
|
86
87
|
get_labels(bud_instance), begins)
|
87
88
|
begins
|
88
89
|
end
|
@@ -103,7 +104,7 @@ module VizUtil #:nodoc: all
|
|
103
104
|
return {} unless bud_instance.respond_to? :lps
|
104
105
|
# sort the paths. sort the paths to the same destination by length.
|
105
106
|
aps = {}
|
106
|
-
ap_interm = bud_instance.lps.sort do |a, b|
|
107
|
+
ap_interm = bud_instance.lps.to_a.sort do |a, b|
|
107
108
|
if a.to == b.to then
|
108
109
|
a.path.length <=> b.path.length
|
109
110
|
else
|
@@ -175,14 +176,14 @@ module VizUtil #:nodoc: all
|
|
175
176
|
rules = {}
|
176
177
|
convertor = Syntax::Convertors::HTML.for_syntax "ruby"
|
177
178
|
shredded_rules.each do |s|
|
178
|
-
fout = File.new("#{output_base}/#{s
|
179
|
+
fout = File.new("#{output_base}/#{s.rule_id}.html", "w+")
|
179
180
|
fout.puts header
|
180
|
-
fout.puts "<h1>Rule #{s
|
181
|
+
fout.puts "<h1>Rule #{s.rule_id}</h1><br>"
|
181
182
|
|
182
|
-
c = convertor.convert(s
|
183
|
+
c = convertor.convert(s.orig_src)
|
183
184
|
c.sub!(/^<pre>/, "<pre class=\"code\" style='font-size:20px'>\n")
|
184
185
|
fout.puts c
|
185
|
-
rules[s
|
186
|
+
rules[s.rule_id] = [s.lhs, s.orig_src]
|
186
187
|
fout.close
|
187
188
|
end
|
188
189
|
|
@@ -308,9 +309,9 @@ END_JS
|
|
308
309
|
data << [time, tab, tup]
|
309
310
|
end
|
310
311
|
end
|
311
|
-
|
312
|
+
|
312
313
|
meta_tabs.each_value do |tab|
|
313
|
-
meta[tab] ||= []
|
314
|
+
meta[tab] ||= []
|
314
315
|
end
|
315
316
|
|
316
317
|
meta[:schminf] = {}
|