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/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] = {}