00001 """
00002 contains a cleaner class that tracks dependencies and removes
00003 any data that is no longer in use and has no unmet dependencies
00004 """
00005 import pdb
00006
00007 __copyright__ = """
00008 Copyright 2008 Sean Ross-Ross
00009 """
00010 __license__ = """
00011 This file is part of SLIMpy .
00012
00013 SLIMpy is free software: you can redistribute it and/or modify
00014 it under the terms of the GNU Lesser General Public License as published by
00015 the Free Software Foundation, either version 3 of the License, or
00016 (at your option) any later version.
00017
00018 SLIMpy is distributed in the hope that it will be useful,
00019 but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00021 GNU Lesser General Public License for more details.
00022
00023 You should have received a copy of the GNU Lesser General Public License
00024 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00025 """
00026
00027
00028
00029
00030 from slimpy_base.Environment.InstanceManager import InstanceManager
00031
00032
00033 class cleaner( object ):
00034 """
00035 cleaner cleans the graph of obsolete data, cleaner
00036 does not necessarily have to remove dead branches from
00037 the graph but the data that the nodes point to.
00038 """
00039
00040 env = InstanceManager()
00041
00042
00043 def __init__( self, graph, depth=1 ):
00044 """
00045 cleaner instance takes a graph and a depth
00046 """
00047 self.graph = graph
00048 self.depth = depth
00049 self.__source = {}
00050 self._stored = set( [] )
00051
00052 self._cleaned = set()
00053
00054 def clean( self, node ):
00055 """
00056 usage: Call clean on a node after the node is finished
00057 adds the dependencies of node to the list of sources by calling add source.
00058 once all of ...
00059 """
00060
00061 for nondep in self._stored.copy():
00062
00063 self.remove( nondep )
00064
00065 log = self.env['record']
00066 print >> log( 10, 'cleaner' ) , "clean called on node %(node)s" %vars()
00067
00068 for prev in self.graph.invAdj( node ):
00069
00070 self.addSource( prev )
00071
00072 def addSource( self, node ):
00073 """
00074 Add a source node to the cleaner.
00075
00076 compares the number of nodes to how many times
00077 node has been added to the cleaner.
00078 for example:
00079 let a subset of a graph be:
00080 data1 -> command1
00081 data1 -> command2
00082 then the number of nodes data1 depends on is 2
00083 when command1 is finished processing Cleaner.Clean(command1) will be called
00084 and Cleaner.Clean(command2) will be called after command2 is finished with
00085 each time Cleaner.addSource(data1) is called
00086 so on the call of Cleaner.Clean(command2) data1 will be removed
00087 by using the method Cleaner.remove(data1)
00088 """
00089
00090 dep = len( self.graph.adj( node ) )
00091
00092 num = self.__source.get( node , 0 )
00093
00094 num += 1
00095
00096 self.__source[node] = num
00097
00098 if num >= dep:
00099
00100 self.remove( node )
00101 self.__source[node] = 0
00102
00103 def remove( self, node ):
00104 """
00105 removes node only if the reference count of node is 1
00106
00107 """
00108
00109 if isinstance( node, tuple ) :
00110 return
00111
00112 table = self.env['table']
00113 slimvars = self.env['slimvars']
00114 log = self.env['record']( 10, 'cleaner' )
00115 log2 = self.env['record']( 1, 'cln' )
00116 refcount = table.getRef( node )
00117 if refcount:
00118 print >> log, 'Cleaner: NOT removing node,\nnode still active refcount=%(refcount)s' %vars()
00119
00120
00121
00122 self._stored.add( node )
00123 return False
00124 elif table.has_active_referers( node ):
00125 print >> log, 'Cleaner: NOT removing node,\nnode still has active referrers' %vars()
00126 self._stored.add( node )
00127 return False
00128 else:
00129 self._stored.discard( node )
00130 item = table[node]
00131
00132 print >> log, 'Cleaner: removing node', item , 'refcount=',refcount
00133
00134
00135 self._cleaned.add( node )
00136
00137 if not slimvars['no_del']:
00138 try:
00139 print >> log2, "Cleaner Removing", item
00140
00141
00142
00143 item.remove()
00144 except AttributeError:
00145 pass
00146
00147 return True
00148
00149 def get_cleaned_nodes(self):
00150 return self._cleaned
00151
00152 def all( func, iterable ):
00153 """
00154 returns true if all values in iterable
00155 evaluate to True
00156 @param iterable: list
00157 """
00158
00159 val = True
00160 for x in iterable:
00161 val = func( x ) and val
00162 return val
00163