bud 0.0.8 → 0.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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] = {}
|