diff options
| author | Casey Dahlin <cdahlin@redhat.com> | 2008-10-08 16:56:17 -0400 |
|---|---|---|
| committer | Casey Dahlin <cdahlin@redhat.com> | 2008-10-08 16:56:17 -0400 |
| commit | bc86c2adc3ac8dbed5667a34398faef10285ac49 (patch) | |
| tree | 6b196165703cb14e74051a8dbaf8b4839d36130f | |
| parent | 77c1ab4d6d490e0e348690eda061b07e9bb98e4f (diff) | |
| download | upstate-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.rb | 65 |
1 files changed, 49 insertions, 16 deletions
@@ -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 |
