lib/openwfe/expool/expstorage.rb in ruote-0.9.18 vs lib/openwfe/expool/expstorage.rb in ruote-0.9.19

- old
+ new

@@ -1,34 +1,34 @@ # #-- # Copyright (c) 2006-2008, Nicolas Modryzk and John Mettraux, OpenWFE.org # All rights reserved. -# -# Redistribution and use in source and binary forms, with or without +# +# Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: -# +# # . Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# . Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation +# list of conditions and the following disclaimer. +# +# . Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. -# +# # . Neither the name of the "OpenWFE" nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. #++ # # @@ -38,366 +38,337 @@ # John Mettraux at openwfe.org # require 'fileutils' -#require 'rufus/lru' +require 'rufus/lru' require 'openwfe/service' require 'openwfe/flowexpressionid' require 'openwfe/rudefinitions' module OpenWFE - # - # This module contains the observe_expool method which binds the - # storage to the expression pool. - # It also features a to_s method for the expression storages including - # it. - # - module ExpressionStorageBase + # + # This module contains the observe_expool method which binds the + # storage to the expression pool. + # It also features a to_s method for the expression storages including + # it. + # + module ExpressionStorageBase - def observe_expool + def observe_expool - get_expression_pool.add_observer(:update) do |channel, fei, fe| - ldebug { ":update for #{fei}" } - self[fei] = fe - end - get_expression_pool.add_observer(:remove) do |channel, fei| - ldebug { ":delete for #{fei}" } - self.delete fei - end - end + get_expression_pool.add_observer(:update) do |channel, fei, fe| + ldebug { ":update for #{fei}" } + self[fei] = fe + end + get_expression_pool.add_observer(:remove) do |channel, fei| + ldebug { ":remove for #{fei}" } + self.delete fei + end + end - # - # a human readable representation of the content of the expression - # storage. - # - # Warning : this will display the content of the real storage, - # (especially when called against a cache). - # - def to_s + # + # a human readable representation of the content of the expression + # storage. + # + # Warning : this will display the content of the real storage, + # (especially when called against a cache). + # + def to_s - s = "\n\n==== #{self.class} ====" + s = "\n\n==== #{self.class} ====" - find_expressions.each do |fexp| + find_expressions.each do |fexp| - s << "\n" - if fexp.kind_of?(RawExpression) - s << "*raw" - else - s << " " - end - s << fexp.fei.to_s - end - s << "\n==== . ====\n" - - s + s << "\n" + if fexp.kind_of?(RawExpression) + s << "*raw" + else + s << " " end + s << fexp.fei.to_s + end + s << "\n==== . ====\n" - # - # This method is used by the various implementations of - # find_expressions() - # - def does_match? (options, fexp_or_fei) + s + end - wfid = options[:wfid] - wfid_prefix = options[:wfid_prefix] - parent_wfid = options[:parent_wfid] + # + # This method is used by the various implementations of + # find_expressions() + # + def does_match? (options, fexp_or_fei) - wfname = options[:wfname] - wfrevision = options[:wfrevision] + wfid = options[:wfid] + wfid_prefix = options[:wfid_prefix] + parent_wfid = options[:parent_wfid] - ic = options[:include_classes] - ec = options[:exclude_classes] - ic = Array(ic) if ic - ec = Array(ec) if ec + wfname = options[:wfname] + wfrevision = options[:wfrevision] - cs = options[:consider_subprocesses] + ic = options[:include_classes] + ec = options[:exclude_classes] + ic = Array(ic) if ic + ec = Array(ec) if ec - ap = options[:applied] + cs = options[:consider_subprocesses] - fexp, fei = if fexp_or_fei.is_a?(FlowExpressionId) - [ nil, fexp_or_fei ] - else - [ fexp_or_fei, fexp_or_fei.fei ] - end + ap = options[:applied] - # - # let's make it verbose... + fexp, fei = if fexp_or_fei.is_a?(FlowExpressionId) + [ nil, fexp_or_fei ] + else + [ fexp_or_fei, fexp_or_fei.fei ] + end - if fexp - return false if (ap == true and not fexp.apply_time) - return false if (ap == false and fexp.apply_time) - return false unless class_accepted?(fexp, ic, ec) - end + # + # let's make it verbose... - return false \ - if wfname and fei.wfname != wfname - return false \ - if wfrevision and fei.wfrevision != wfrevision + if fexp + return false if (ap == true and not fexp.apply_time) + return false if (ap == false and fexp.apply_time) + return false unless class_accepted?(fexp, ic, ec) + end - return false \ - if cs and fei.sub_instance_id != "" - return false \ - if wfid and fei.wfid != wfid - return false \ - if wfid_prefix and not fei.wfid.match("^#{wfid_prefix}") - return false \ - if parent_wfid and not fei.parent_wfid == parent_wfid + return false \ + if wfname and fei.wfname != wfname + return false \ + if wfrevision and fei.wfrevision != wfrevision - true - end + return false \ + if cs and fei.sub_instance_id != "" + return false \ + if wfid and fei.wfid != wfid + return false \ + if wfid_prefix and not fei.wfid.match("^#{wfid_prefix}") + return false \ + if parent_wfid and not fei.parent_wfid == parent_wfid - # - # Returns true if the given expression is in the list of included - # classes or false if it's in the list of excluded classes... - # - # include_classes has precedence of exclude_classes. - # - def class_accepted? (fexp, include_classes, exclude_classes) - - return false if include_classes and (not include_classes.find do |klazz| - fexp.is_a?(klazz) - end) - return false if exclude_classes and exclude_classes.find do |klazz| - fexp.is_a?(klazz) - end - - true - end + true end # - # This cache uses a LruHash (Least Recently Used) to store expressions. - # If an expression is not cached, the 'real storage' is consulted. - # The real storage is supposed to be the service named - # "expressionStorage.1" + # Returns true if the given expression is in the list of included + # classes or false if it's in the list of excluded classes... # - class CacheExpressionStorage - include ServiceMixin - include OwfeServiceLocator - include ExpressionStorageBase + # include_classes has precedence of exclude_classes. + # + def class_accepted? (fexp, include_classes, exclude_classes) - # - # under 20 stored expressions, the unit tests for the - # CachedFilePersistedEngine do fail because the persistent storage - # behind the cache hasn't the time to flush its work queue. - # a min size limit has been set to 77. - # - MIN_SIZE = 77 + return false if include_classes and (not include_classes.find do |klazz| + fexp.is_a?(klazz) + end) + return false if exclude_classes and exclude_classes.find do |klazz| + fexp.is_a?(klazz) + end - DEFAULT_SIZE = 5000 + true + end + end - def initialize (service_name, application_context) + # + # This cache uses a LruHash (Least Recently Used) to store expressions. + # If an expression is not cached, the 'real storage' is consulted. + # The real storage is supposed to be the service named + # "expressionStorage.1" + # + class CacheExpressionStorage + include ServiceMixin + include OwfeServiceLocator + include ExpressionStorageBase - super() + # + # under 20 stored expressions, the unit tests for the + # CachedFilePersistedEngine do fail because the persistent storage + # behind the cache hasn't the time to flush its work queue. + # a min size limit has been set to 77. + # + MIN_SIZE = 77 - service_init(service_name, application_context) + DEFAULT_SIZE = 5000 - size = @application_context[:expression_cache_size] || DEFAULT_SIZE - size = MIN_SIZE unless size > MIN_SIZE + def initialize (service_name, application_context) - linfo { "new() size is #{size}" } + super() - @cache = LruHash.new(size) + service_init(service_name, application_context) - @real_storage = nil + size = @application_context[:expression_cache_size] || DEFAULT_SIZE + size = MIN_SIZE unless size > MIN_SIZE - observe_expool - end + linfo { "new() size is #{size}" } - def [] (fei) + @cache = LruHash.new(size) - #ldebug { "[] size is #{@cache.size}" } - #ldebug { "[] (sz #{@cache.size}) for #{fei.to_debug_s}" } + @real_storage = nil - fe = @cache[fei.hash] - return fe if fe + observe_expool + end - #ldebug { "[] (reload) for #{fei.to_debug_s}" } + def [] (fei) - fe = get_real_storage[fei] + #ldebug { "[] size is #{@cache.size}" } + #ldebug { "[] (sz #{@cache.size}) for #{fei.to_debug_s}" } - unless fe - #ldebug { "[] (reload) miss for #{fei.to_debug_s}" } - return nil - end + fe = @cache[fei.hash] + return fe if fe - @cache[fei.hash] = fe + #ldebug { "[] (reload) for #{fei.to_debug_s}" } - fe - end + fe = get_real_storage[fei] - def []= (fei, fe) + unless fe + #ldebug { "[] (reload) miss for #{fei.to_debug_s}" } + return nil + end - ldebug { "[]= caching #{fei}" } + @cache[fei.hash] = fe - @cache[fei.hash] = fe - end + fe + end - def delete (fei) + def []= (fei, fe) - @cache.delete fei.hash - end + ldebug { "[]= caching #{fei}" } - def length + @cache[fei.hash] = fe + end - @cache.length - end + def delete (fei) - alias :size :length + @cache.delete fei.hash + end - def clear + def length - @cache.clear - end + @cache.length + end - alias :purge :clear + alias :size :length - # - # This implementations of find_expressions() immediately passes - # the call to the underlying real storage. - # - def find_expressions (options={}) + def clear - get_real_storage.find_expressions options - end + @cache.clear + end - # - # Attempts at fetching the root expression of a given process - # instance. - # - def fetch_root (wfid) + alias :purge :clear - # - # at first, look in the cache + # + # This implementations of find_expressions() immediately passes + # the call to the underlying real storage. + # + def find_expressions (options={}) - @cache.each do |hashed_fei, fexp| + get_real_storage.find_expressions options + end - return fexp \ - if fexp.fei.wfid == wfid and fexp.is_a?(DefineExpression) - end + # + # Attempts at fetching the root expression of a given process + # instance. + # + def fetch_root (wfid) - get_real_storage.fetch_root wfid - end + # + # at first, look in the cache - protected + @cache.each do |hashed_fei, fexp| - # - # Returns the "real storage" i.e. the storage that does the real - # persistence behind this "cache storage". - # - def get_real_storage + return fexp \ + if fexp.fei.wfid == wfid and fexp.is_a?(DefineExpression) + end - #return @real_storage if @real_storage - #@real_storage = - # @application_context[S_EXPRESSION_STORAGE + ".1"] - #@real_storage - - @application_context["expressionStorage.1"] - end + get_real_storage.fetch_root wfid end - - # - # Memory consuming in-memory storage. - # No memory limit, puts everything in a Hash - # - class InMemoryExpressionStorage < Hash - include ServiceMixin - include OwfeServiceLocator - include ExpressionStorageBase - - def initialize (service_name, application_context) - service_init service_name, application_context + protected - observe_expool - end + # + # Returns the "real storage" i.e. the storage that does the real + # persistence behind this "cache storage". + # + def get_real_storage - alias :purge :clear + @application_context[:s_expression_storage__1] + end + end - #-- - # Allows to pass a block to each expressions of a given kind (type). - # - #def each_of_kind (kind, &block) - # self.each_value do |fexp| - # block.call(fexp.fei, fexp) if fexp.kind_of?(kind) - # end - #end - # - # An iterator on the expression stored in here. - # - #def each (wfid_prefix=nil, &block) - # if wfid_prefix - # super() do |fei, fexp| - # next unless fei.wfid.match "^#{wfid_prefix}" - # block.call fei, fexp - # end - # else - # super(&block) - # end - #end - #alias :real_each :each - #++ + # + # Memory consuming in-memory storage. + # No memory limit, puts everything in a Hash + # + class InMemoryExpressionStorage < Hash + include ServiceMixin + include OwfeServiceLocator + include ExpressionStorageBase - # - # Finds expressions matching the given criteria (returns a list - # of expressions). - # - # This methods is called by the expression pool, it's thus not - # very "public" (not used directly by integrators, who should - # just focus on the methods provided by the Engine). - # - # :wfid :: - # will list only one process, - # <tt>:wfid => '20071208-gipijiwozo'</tt> - # :parent_wfid :: - # will list only one process, and its subprocesses, - # <tt>:parent_wfid => '20071208-gipijiwozo'</tt> - # :consider_subprocesses :: - # if true, "process-definition" expressions - # of subprocesses will be returned as well. - # :wfid_prefix :: - # allows your to query for specific workflow instance - # id prefixes. for example : - # <tt>:wfid_prefix => "200712"</tt> - # for the processes started in December. - # :include_classes :: - # excepts a class or an array of classes, only instances of these - # classes will be returned. Parent classes or mixins can be - # given. - # <tt>:includes_classes => OpenWFE::SequenceExpression</tt> - # :exclude_classes :: - # works as expected. - # :wfname :: - # will return only the expressions who belongs to the given - # workflow [name]. - # :wfrevision :: - # usued in conjuction with :wfname, returns only the expressions - # with a given workflow revision. - # :applied :: - # if this option is set to true, will only return the expressions - # that have been applied (exp.apply_time != nil). - # - def find_expressions (options={}) + def initialize (service_name, application_context) - values.find_all do |fexp| - does_match? options, fexp - end - end + service_init service_name, application_context - # - # Attempts at fetching the root expression of a given process - # instance. - # - def fetch_root (wfid) + observe_expool + end - find_expressions( - :wfid => wfid, - :include_classes => DefineExpression)[0] - end + alias :purge :clear + # + # Finds expressions matching the given criteria (returns a list + # of expressions). + # + # This methods is called by the expression pool, it's thus not + # very "public" (not used directly by integrators, who should + # just focus on the methods provided by the Engine). + # + # :wfid :: + # will list only one process, + # <tt>:wfid => '20071208-gipijiwozo'</tt> + # :parent_wfid :: + # will list only one process, and its subprocesses, + # <tt>:parent_wfid => '20071208-gipijiwozo'</tt> + # :consider_subprocesses :: + # if true, "process-definition" expressions + # of subprocesses will be returned as well. + # :wfid_prefix :: + # allows your to query for specific workflow instance + # id prefixes. for example : + # <tt>:wfid_prefix => "200712"</tt> + # for the processes started in December. + # :include_classes :: + # excepts a class or an array of classes, only instances of these + # classes will be returned. Parent classes or mixins can be + # given. + # <tt>:includes_classes => OpenWFE::SequenceExpression</tt> + # :exclude_classes :: + # works as expected. + # :wfname :: + # will return only the expressions who belongs to the given + # workflow [name]. + # :wfrevision :: + # usued in conjuction with :wfname, returns only the expressions + # with a given workflow revision. + # :applied :: + # if this option is set to true, will only return the expressions + # that have been applied (exp.apply_time != nil). + # + def find_expressions (options={}) + + values.find_all do |fexp| + does_match? options, fexp + end end + + # + # Attempts at fetching the root expression of a given process + # instance. + # + def fetch_root (wfid) + + find_expressions( + :wfid => wfid, + :include_classes => DefineExpression)[0] + end + + end end