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/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
- scratch(name, schema)
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 syncronously-flushed persistent collection. default schema <tt>[:key] => [:val]</tt>.
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
@@ -2,8 +2,9 @@ require 'dbm'
2
2
 
3
3
  module Bud
4
4
  # Persistent table implementation based on ndbm.
5
- class BudDbmTable < BudCollection # :nodoc: all
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
- tuple_accessors(t)
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
- merge_to_db(@delta)
134
- @delta = @new_delta
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.each do |tuple|
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
- raise Bud::Error, "orphaned tuples in @delta for #{@tabname}" unless @delta.empty?
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
- merge_to_db(@pending)
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 < BudCollection # :nodoc: all
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] = tuple_accessors([c, data])
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
- end
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
- write_graphs(tabinf, bit, bud_instance.t_cycle,
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, bud_instance.meta_parser.depanalysis, -1, nil,
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[0]}.html", "w+")
179
+ fout = File.new("#{output_base}/#{s.rule_id}.html", "w+")
179
180
  fout.puts header
180
- fout.puts "<h1>Rule #{s[0]}</h1><br>"
181
+ fout.puts "<h1>Rule #{s.rule_id}</h1><br>"
181
182
 
182
- c = convertor.convert(s[4])
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[0]] = [s[1], s[4]]
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] = {}