class LibRebl

Library of functions used by rebl. More generally, this can be viewed as a way to have a bud class that you can add and remove rules from, and that you can step through the execution of.

Attributes

ip[R]
port[R]
rebl_class_inst[R]
rules[RW]
state[RW]

Public Class Methods

new(ip, port) click to toggle source
# File lib/bud/rebl.rb, line 215
def initialize(ip, port)
  @ip = ip
  @port = port
  @rules = {}
  @ruleid = 0
  @state = {}
  @stateid = 0
  @rebl_class = nil
  @rebl_class_inst = nil
  @old_inst = nil
  reinstantiate
end

Public Instance Methods

add_collection(c) click to toggle source

Declares a new collection.

# File lib/bud/rebl.rb, line 259
def add_collection(c)
  @state[@stateid += 1] = c
  begin
    reinstantiate
  rescue Exception
    @state.delete(@stateid)
    raise
  end
end
add_rule(r) click to toggle source

Adds a new rule at the current time; only derives tuples based on data that exists at the current or a future time.

# File lib/bud/rebl.rb, line 282
def add_rule(r)
  @rules[@ruleid += 1] = r
  begin
    reinstantiate
  rescue Exception
    @rules.delete(@ruleid)
    raise
  end
end
del_rule(rid) click to toggle source

Deactivates a rule at the current time; any tuples derived by the rule at a previous time are still available.

# File lib/bud/rebl.rb, line 271
def del_rule(rid)
  unless @rules.has_key? rid
    puts "No rule with ID #{rid}"
    return
  end
  @rules.delete(rid)
  reinstantiate
end
dump(c) click to toggle source

Dumps the contents of a table at the current time.

# File lib/bud/rebl.rb, line 244
def dump(c)
  if c.nil?
    puts "Error: dump must be passed a collection name"
  elsif @rebl_class_inst.tables.has_key? c.to_sym
    tups = @rebl_class_inst.tables[c.to_sym].to_a.sort
    puts(tups.empty? ? "(empty)" : tups.sort.map{|t| "#{t}"}.join("\n"))
  elsif @rebl_class_inst.lattices.has_key? c.to_sym
    val = @rebl_class_inst.lattices[c.to_sym].current_value
    puts val.inspect
  else
    puts "Error: non-existent collection \"#{c}\""
  end
end
mk_rebl_class() click to toggle source
# File lib/bud/rebl.rb, line 292
  def mk_rebl_class
    @@classid += 1
    cls_name = "ReblClass#{@@classid}"

    str = ""
    str =<<-EOS
      $BUD_SAFE=1
      class #{cls_name} < ReblBase
        include Bud
      EOS
    unless @state.empty?
      str += "state do\n" + @state.values.join("\n") + "\nend\n"
    end
    unless @rules.empty?
      str += "bloom :rebl_rules do\n" + @rules.sort.map {|_,r| r}.join("\n") + "\nend\n"
    end
    str += "\nend\n"
    f = Tempfile.new("rebl")
    f.write(str)
    f.close
    begin
      load f.path
      return eval cls_name  # return the class object
    rescue
      $stderr.puts "Unable to eval the following code:\n" + str
      raise
    ensure
      f.unlink
    end
  end
run() click to toggle source

Runs the bud instance (until a breakpoint, or stop() is called)

# File lib/bud/rebl.rb, line 229
def run
  @rebl_class_inst.run_bg
end
stop() click to toggle source

Stops the bud instance (and then performs another tick)

# File lib/bud/rebl.rb, line 234
def stop
  @rebl_class_inst.pause
end
tick(x=1) click to toggle source

Ticks the bud instance a specified integer number of times.

# File lib/bud/rebl.rb, line 239
def tick(x=1)
  x.times {@rebl_class_inst.sync_do}
end

Private Instance Methods

reinstantiate() click to toggle source
# File lib/bud/rebl.rb, line 324
def reinstantiate
  @rebl_class = mk_rebl_class

  @old_inst = @rebl_class_inst
  @rebl_class_inst = @rebl_class.new(:signal_handling => :none, :ip => @ip,
                                     :port => @port)

  # Stop the old instance. We want to copy the old instance's state over to
  # the new instance and then startup the new instance. Any network messages
  # received before the new instance has been started will be lost, but that
  # can't easily be avoided; the best we can do is ensure we get a consistent
  # snapshot of the old instance's state.
  @old_inst.stop if @old_inst

  # Copy the tables over.
  if @old_inst
    @rebl_class_inst.tables.merge!(@old_inst.tables.reject do |k,v|
                                     @@builtin_tables.include? k
                                   end)
    @rebl_class_inst.tables.each do |k,v|
      v.invalidate_cache
    end
    @rebl_class_inst.channels.merge!(@old_inst.channels.reject do |k,v|
                                       @@builtin_tables.include? k
                                     end)
    @rebl_class_inst.dbm_tables.merge! @old_inst.dbm_tables
    @rebl_class_inst.zk_tables.merge! @old_inst.zk_tables
    @rebl_class_inst.lattices.merge! @old_inst.lattices

    # Fix the bud instance pointers from copied tables.
    @rebl_class_inst.tables.each_value do |v|
      v.bud_instance = @rebl_class_inst
    end
    @rebl_class_inst.lattices.each_value do |v|
      v.bud_instance = @rebl_class_inst
    end
  end

  # Run lazily in background, shutting down old instance.
  begin
    # Lazify the instance upon a breakpoint (no effect if instance is
    # already lazy)
    @rebl_class_inst.register_callback(:rebl_breakpoint) do
      @rebl_class_inst.pause
    end
    @rebl_class_inst.start
    @ip = @rebl_class_inst.ip
    @port = @rebl_class_inst.port
    puts "Listening on #{@ip}:#{@port}" unless @old_inst
  rescue Exception
    # The above two need to be atomic, or we're in trouble.
    puts "unrecoverable error, please file a bug: #{$!}"
    abort
  end
end