summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCasey Dahlin <cdahlin@redhat.com>2008-10-08 16:56:17 -0400
committerCasey Dahlin <cdahlin@redhat.com>2008-10-08 16:56:17 -0400
commitbc86c2adc3ac8dbed5667a34398faef10285ac49 (patch)
tree6b196165703cb14e74051a8dbaf8b4839d36130f
parent77c1ab4d6d490e0e348690eda061b07e9bb98e4f (diff)
downloadupstate-bc86c2adc3ac8dbed5667a34398faef10285ac49.tar.gz
upstate-bc86c2adc3ac8dbed5667a34398faef10285ac49.tar.xz
upstate-bc86c2adc3ac8dbed5667a34398faef10285ac49.zip
Use DSTuple objects for State deps
State dependencies are now pairings of Dependency objects and the States which resolve them
-rw-r--r--state.rb65
1 files changed, 49 insertions, 16 deletions
diff --git a/state.rb b/state.rb
index ccfe132..c8a39b2 100644
--- a/state.rb
+++ b/state.rb
@@ -51,8 +51,7 @@ class State
@@states = Set.new # Set of activatable states
@@state_types = Set.new # Set of state types
- # Create a new state. +deps+ is a list of State objects, not Dependency
- # objects
+ # Create a new state. +deps+ is a list of DSTuple objects
def initialize(deps)
raise NoMethodError if self.class == State
@@ -79,6 +78,7 @@ class State
def check_deps
trace "Dep check on #{self}"
@deps.each do |dep|
+ dep = dep.state
next if dep.status != :down
raise ConsistencyFault, "Lost dep on #{dep} without notify for #{self}" if @status != :down
trace " Purging..."
@@ -161,7 +161,7 @@ class State
else
trace "#{self} becomes defunct"
end
- @deps.each{ |x| x.release(self) }
+ @deps.each{ |x| x.state.release(self) }
@status = :down
State.gc
State.depsolve_all
@@ -183,16 +183,16 @@ class State
# Our ID is a function of our class and deps
def hash
- @deps.inject(self.class.hash){ |x,y| (x ** 2 + y.object_id) % 0x4000000000000000 }
+ self.class.hash ** 2 + self.params.sort.hash % 0x4000000000000000
end
# A state is rooted in a set of states if any state in the set which it _may_
# depend on, it _does_ depend on, and if all of its depended states are rooted
# in the set.
def rooted_in(set)
- @deps.inject(true){ |x,y| x and y.rooted_in set } and \
+ @deps.inject(true){ |x,y| x and y.state.rooted_in set } and \
self.class.depends.map{ |x| set.select{ |y| x === y } } \
- .inject([]){ |x, y| x+y }.to_set.subset? @deps
+ .inject([]){ |x, y| x+y }.to_set.subset? @deps.map{ |x| x.state }.to_set
end
# Create a new type of state. +name+ is capitalized and postfixed with "State"
@@ -238,7 +238,10 @@ class State
# be met
def State.depsolve
active_states = @@states.select{ |x| x.status == :up }
- candidates = @depends.map{ |d| active_states.select{ |s| d.match s } }
+ candidates = @depends.map do |d|
+ active_states.map{ |s| DSTuple.new(d, s) }.select{ |x| x.valid? }
+ end
+
return nil if candidates.include? []
unless candidates == []
@@ -248,11 +251,8 @@ class State
candidates = [Set.new]
end
- candidates.reject! do |dset|
- active_states.select{ |x| x.is_a? self and x.deps == dset }.size > 0
- end
-
candidates.each{ |x| self.new x }
+ nil
end
# Depsolve all state classes. This method is not defined in subclasses of
@@ -278,7 +278,7 @@ private
return if @status == :up
trace "Raising #{self}"
@status = :rising
- @deps.each{ |x| x.hold(self) }
+ @deps.each{ |x| x.state.hold(self) }
self.class.rising_edge.call(params)
@status = :up
State.depsolve_all
@@ -367,14 +367,19 @@ which certain parameters must conform to, but it does not necessarily contain
enough info to define a state in its entirety.
=end
class Dependency
+ attr :params # What parameters do we expect?
+ attr :stateclass # What class of state do we match?
+ attr :remap # Parameters our dependent wants to get under another name.
+
# A dependency is created from a class of state to match, and a hash of
# parameters. The parameters in the hash can be string values to match or
# Regex objects
- def initialize(stateclass, params = {})
+ def initialize(stateclass, params = {}, remap = {})
raise TypeError unless State > stateclass
raise TypeError unless params.is_a? Hash
@stateclass = stateclass
@params = params
+ @remap = remap
end
# Two dependencies are equal if any given set would be either matched by both
@@ -399,10 +404,38 @@ class Dependency
end
return true
end
+end
-protected
- attr :stateclass # What class of state do we match?
- attr :params # What parameters do we expect?
+=begin rdoc
+A DSTuple is a pairing of a Dependency and a state that meets it.
+=end
+class DSTuple
+ attr :dep # What dependency do we resolve?
+ attr :state # How do we resolve it?
+
+ # DSTuples are born of a Dependency, and a State which satisfies it
+ def initialize(dep, state)
+ @dep = dep
+ @state = state
+ end
+
+ # Is our state rooted in the given set of DSTuples?
+ def rooted_in(set)
+ @state.rooted_in set.map{ |x| x.state }
+ end
+
+ # Does this DSTuple represent a sane resolution?
+ def valid?
+ @dep === @state
+ end
+
+ # What parameters does this tuple provide to its parent?
+ def params
+ result = {}
+ input = @state.params
+ @dep.params.each_key{ |x| result[(@dep.remap[x] or x)] = input[x] }
+ result
+ end
end
=begin rdoc