bug fixes, multiple pools of traversal starting points

This commit is contained in:
Darren Ranalli 2007-04-17 06:52:16 +00:00
parent 2e55c5bc14
commit 2144050758

View File

@ -1,12 +1,12 @@
from pandac.PandaModules import PStatCollector from pandac.PandaModules import PStatCollector
from direct.directnotify.DirectNotifyGlobal import directNotify from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.PythonUtil import Queue, invertDictLossless from direct.showbase.PythonUtil import Queue, invertDictLossless, makeFlywheelGen
from direct.showbase.PythonUtil import itype, serialNum, safeRepr, fastRepr from direct.showbase.PythonUtil import itype, serialNum, safeRepr, fastRepr
from direct.showbase.Job import Job from direct.showbase.Job import Job
import types, weakref, random, __builtin__ import types, weakref, random, __builtin__
def _createContainerLeak(): def _createContainerLeak():
def leakContainer(task): def leakContainer(task=None):
base = getBase() base = getBase()
if not hasattr(base, 'leakContainer'): if not hasattr(base, 'leakContainer'):
base.leakContainer = {} base.leakContainer = {}
@ -22,8 +22,10 @@ def _createContainerLeak():
ContainerLeakDetector.notify.debug( ContainerLeakDetector.notify.debug(
'removing reference to leakContainer key %s so it will be garbage-collected' % safeRepr(key)) 'removing reference to leakContainer key %s so it will be garbage-collected' % safeRepr(key))
del base.leakContainer[key] del base.leakContainer[key]
return task.cont taskMgr.doMethodLater(10, leakContainer, 'leakContainer-%s' % serialNum())
task = taskMgr.add(leakContainer, 'leakContainer-%s' % serialNum()) if task:
return task.done
leakContainer()
class NoDictKey: class NoDictKey:
pass pass
@ -133,16 +135,19 @@ class ContainerRef:
collection of the container if possible collection of the container if possible
stored as a series of 'indirections' (obj.foo -> '.foo', dict[key] -> '[key]', etc.) stored as a series of 'indirections' (obj.foo -> '.foo', dict[key] -> '[key]', etc.)
""" """
notify = directNotify.newCategory("ContainerRef")
class FailedEval(Exception): class FailedEval(Exception):
pass pass
def __init__(self, indirection, other=None): def __init__(self, indirection, other=None):
self._indirections = [] self._indirections = []
# if no other passed in, try ContainerRef.BaseRef # are we building off of an existing ref?
if other is not None: if other is not None:
for ind in other._indirections: for ind in other._indirections:
self.addIndirection(ind) self.addIndirection(ind)
self.addIndirection(indirection) self.addIndirection(indirection)
self.notify.debug(repr(self))
def destroy(self): def destroy(self):
# re-entrant # re-entrant
@ -154,20 +159,27 @@ class ContainerRef:
indirection.acquire() indirection.acquire()
self._indirections.append(indirection) self._indirections.append(indirection)
def _getContainerByEval(self, evalStr): def getNumIndirections(self):
return len(self._indirections)
def _getContainerByEval(self, evalStr, curObj=None):
if curObj is not None:
# eval('curObj.foo.bar.someDict')
evalStr = 'curObj%s' % evalStr
else:
# this eval is not based off of curObj, use the global__builtin__ namespace
# put __builtin__ at the start if it's not already there
bis = '__builtin__'
if evalStr[:len(bis)] != bis:
evalStr = '%s.%s' % (bis, evalStr)
try: try:
container = eval(evalStr) container = eval(evalStr)
except NameError, ne: except NameError, ne:
return None return None
except AttributeError, ne:
return None
return container return container
def _evalWithObj(self, evalStr, curObj=None):
# eval an evalStr, optionally based off of an existing object
if curObj is not None:
# eval('curObj.foo.bar.someDict')
evalStr = 'curObj%s' % evalStr
return self._getContainerByEval(evalStr)
def getContainer(self): def getContainer(self):
# try to get a handle on the container by eval'ing and looking things # try to get a handle on the container by eval'ing and looking things
# up in dictionaries, depending on the type of each indirection # up in dictionaries, depending on the type of each indirection
@ -184,7 +196,7 @@ class ContainerRef:
# build up a string to be eval'd # build up a string to be eval'd
evalStr += indirection.getString() evalStr += indirection.getString()
else: else:
curObj = self._evalWithObj(evalStr, curObj) curObj = self._getContainerByEval(evalStr, curObj=curObj)
if curObj is None: if curObj is None:
raise FailedEval(evalStr) raise FailedEval(evalStr)
# try to look up this key in the curObj dictionary # try to look up this key in the curObj dictionary
@ -194,7 +206,8 @@ class ContainerRef:
yield None yield None
indirection.release() indirection.release()
yield self._evalWithObj(evalStr, curObj) # TODO: check that this is still the object we originally pointed to
yield self._getContainerByEval(evalStr, curObj=curObj)
def getNameGen(self): def getNameGen(self):
str = '' str = ''
@ -236,32 +249,43 @@ class FindContainers(Job):
Job.__init__(self, name) Job.__init__(self, name)
self._leakDetector = leakDetector self._leakDetector = leakDetector
self._id2ref = self._leakDetector._id2ref self._id2ref = self._leakDetector._id2ref
# these hold objects that we should start traversals from often and not-as-often,
# respectively
self._id2baseStartRef = {}
self._id2discoveredStartRef = {}
# these are working copies so that our iterations aren't disturbed by changes to the
# definitive ref sets
self._baseStartRefWorkingList = ScratchPad(refGen=nullGen(),
source=self._id2baseStartRef)
self._discoveredStartRefWorkingList = ScratchPad(refGen=nullGen(),
source=self._id2discoveredStartRef)
self.notify = self._leakDetector.notify self.notify = self._leakDetector.notify
ContainerLeakDetector.addPrivateObj(self.__dict__) ContainerLeakDetector.addPrivateObj(self.__dict__)
# set up the base/starting object # set up the base containers, the ones that hold most objects
self._baseObjRef = ContainerRef(Indirection(evalStr='__builtin__.__dict__')) ref = ContainerRef(Indirection(evalStr='__builtin__.__dict__'))
for i in self._nameContainerGen(__builtin__.__dict__, self._baseObjRef): self._id2baseStartRef[id(__builtin__.__dict__)] = ref
for i in self._addContainerGen(__builtin__.__dict__, ref):
pass pass
try: try:
base base
except: except:
pass pass
else: else:
self._baseObjRef = ContainerRef(Indirection(evalStr='base.__dict__')) ref = ContainerRef(Indirection(evalStr='base.__dict__'))
for i in self._nameContainerGen(base.__dict__, self._baseObjRef): self._id2baseStartRef[id(base.__dict__)] = ref
for i in self._addContainerGen(base.__dict__, ref):
pass pass
try: try:
simbase simbase
except: except:
pass pass
else: else:
self._baseObjRef = ContainerRef(Indirection(evalStr='simbase.__dict__')) ref = ContainerRef(Indirection(evalStr='simbase.__dict__'))
for i in self._nameContainerGen(simbase.__dict__, self._baseObjRef): self._id2baseStartRef[id(simbase.__dict__)] = ref
for i in self._addContainerGen(simbase.__dict__, ref):
pass pass
self._curObjRef = self._baseObjRef
def destroy(self): def destroy(self):
ContainerLeakDetector.removePrivateObj(self.__dict__) ContainerLeakDetector.removePrivateObj(self.__dict__)
Job.destroy(self) Job.destroy(self)
@ -269,6 +293,14 @@ class FindContainers(Job):
def getPriority(self): def getPriority(self):
return Job.Priorities.Low return Job.Priorities.Low
@staticmethod
def getStartObjAffinity(startObj):
# how good of a starting object is this object for traversing the object graph?
try:
return len(startObj)
except:
return 1
def _isDeadEnd(self, obj, objName=None): def _isDeadEnd(self, obj, objName=None):
if type(obj) in (types.BooleanType, types.BuiltinFunctionType, if type(obj) in (types.BooleanType, types.BuiltinFunctionType,
types.BuiltinMethodType, types.ComplexType, types.BuiltinMethodType, types.ComplexType,
@ -293,19 +325,14 @@ class FindContainers(Job):
return True return True
return False return False
def _isContainer(self, obj): def _hasLength(self, obj):
try: try:
len(obj) len(obj)
except: except:
return False return False
return True return True
def _nameContainerGen(self, cont, objRef): def _addContainerGen(self, cont, objRef):
"""
if self.notify.getDebug():
self.notify.debug('_nameContainer: %s' % objRef)
#printStack()
"""
contId = id(cont) contId = id(cont)
# if this container is new, or the objRef repr is shorter than what we already have, # if this container is new, or the objRef repr is shorter than what we already have,
# put it in the table # put it in the table
@ -319,44 +346,111 @@ class FindContainers(Job):
self._leakDetector.removeContainerById(contId) self._leakDetector.removeContainerById(contId)
self._id2ref[contId] = objRef self._id2ref[contId] = objRef
def _addDiscoveredStartRef(self, obj, ref):
# we've discovered an object that can be used to start an object graph traversal
objId = id(obj)
if objId in self._id2discoveredStartRef:
existingRef = self._id2discoveredStartRef[objId]
if type(existingRef) not in (types.IntType, types.LongType):
if (existingRef.getNumIndirections() >=
ref.getNumIndirections()):
# the ref that we already have is more concise than the new ref
return
if objId in self._id2ref:
if (self._id2ref[objId].getNumIndirections() >=
ref.getNumIndirections()):
# the ref that we already have is more concise than the new ref
return
storedItem = ref
# if we already are storing a reference to this object, don't store a second reference
if objId in self._id2ref:
storedItem = objId
self._id2discoveredStartRef[objId] = storedItem
def run(self): def run(self):
try: try:
# this toggles between the sets of start refs every time we start a new traversal
workingListSelector = loopGen([self._baseStartRefWorkingList,
self._discoveredStartRefWorkingList])
# this holds the current step of the current traversal
curObjRef = None
while True: while True:
# yield up here instead of at the end, since we skip back to the # yield up here instead of at the end, since we skip back to the
# top of the while loop from various points # top of the while loop from various points
yield None yield None
#import pdb;pdb.set_trace() #import pdb;pdb.set_trace()
curObj = None if curObjRef is None:
if self._curObjRef is None: # choose an object to start a traversal from
self._curObjRef = self._baseObjRef startRefWorkingList = workingListSelector.next()
try:
for result in self._curObjRef.getContainer():
yield None
curObj = result
except:
self.notify.debug('lost current container: %s' % self._curObjRef)
# that container is gone, try again
self._curObjRef = None
continue
self.notify.debug('--> %s' % self._curObjRef)
# keep a copy of this obj's eval str, it might not be in _id2ref # grab the next start ref from this sequence and see if it's still valid
curObjRef = self._curObjRef while True:
# if we hit a dead end, start over at a container we know about yield None
self._curObjRef = None try:
curObjRef = startRefWorkingList.refGen.next()
break
except StopIteration:
# we've run out of refs, grab a new set
if len(startRefWorkingList.source) == 0:
# ref set is empty, choose another
break
# make a generator that yields containers a # of times that is
# proportional to their length
for flywheel in makeFlywheelGen(
startRefWorkingList.source.values(),
countFunc=lambda x: self.getStartObjAffinity(x),
scale=.05):
yield None
startRefWorkingList.refGen = flywheel
if curObjRef is None:
# this ref set is empty, choose another
# the base set should never be empty (__builtin__ etc.)
continue
# do we need to go look up the object in _id2ref? sometimes we do that
# to avoid storing multiple redundant refs to a single item
if type(curObjRef) in (types.IntType, types.LongType):
startId = curObjRef
curObjRef = None
try:
for containerRef in self._leakDetector.getContainerByIdGen(startId):
yield None
except:
# ref is invalid
self.notify.debug('invalid startRef, stored as id %s' % startId)
self._leakDetector.removeContainerById(startId)
continue
curObjRef = containerRef
try:
for curObj in curObjRef.getContainer():
yield None
except:
self.notify.debug('lost current container, ref.getContainer() failed')
# that container is gone, try again
curObjRef = None
continue
self.notify.debug('--> %s' % curObjRef)
#import pdb;pdb.set_trace()
# store a copy of the current objRef
parentObjRef = curObjRef
# if we hit a dead end, start over from another container
curObjRef = None
if type(curObj) in (types.ModuleType, types.InstanceType): if type(curObj) in (types.ModuleType, types.InstanceType):
child = curObj.__dict__ child = curObj.__dict__
isContainer = self._isContainer(child) hasLength = self._hasLength(child)
notDeadEnd = not self._isDeadEnd(child) notDeadEnd = not self._isDeadEnd(child)
if isContainer or notDeadEnd: if hasLength or notDeadEnd:
objRef = ContainerRef(Indirection(evalStr='.__dict__'), curObjRef) objRef = ContainerRef(Indirection(evalStr='.__dict__'), parentObjRef)
yield None yield None
if isContainer: if hasLength:
for i in self._nameContainerGen(child, objRef): for i in self._addContainerGen(child, objRef):
yield None yield None
if notDeadEnd: if notDeadEnd:
self._curObjRef = objRef self._addDiscoveredStartRef(child, objRef)
curObjRef = objRef
continue continue
if type(curObj) is types.DictType: if type(curObj) is types.DictType:
@ -365,47 +459,46 @@ class FindContainers(Job):
keys = curObj.keys() keys = curObj.keys()
# we will continue traversing the object graph via one key of the dict, # we will continue traversing the object graph via one key of the dict,
# choose it at random without taking a big chunk of CPU time # choose it at random without taking a big chunk of CPU time
numKeysLeft = len(keys) numKeysLeft = len(keys) + 1
nextObjRef = None
for key in keys: for key in keys:
yield None yield None
numKeysLeft -= 1
try: try:
attr = curObj[key] attr = curObj[key]
except KeyError, e: except KeyError, e:
# this is OK because we are yielding during the iteration # this is OK because we are yielding during the iteration
self.notify.debug('could not index into %s with key %s' % (curObjRef, safeRepr(key))) self.notify.debug('could not index into %s with key %s' % (
parentObjRef, safeRepr(key)))
continue continue
isContainer = self._isContainer(attr) hasLength = self._hasLength(attr)
notDeadEnd = False notDeadEnd = False
if nextObjRef is None: # if we haven't picked the next ref, check if this one is a candidate
if curObjRef is None:
notDeadEnd = not self._isDeadEnd(attr, key) notDeadEnd = not self._isDeadEnd(attr, key)
if isContainer or notDeadEnd: if hasLength or notDeadEnd:
if curObj is __builtin__.__dict__: if curObj is __builtin__.__dict__:
objRef = ContainerRef(Indirection(evalStr=key)) objRef = ContainerRef(Indirection(evalStr='%s' % key))
else: else:
objRef = ContainerRef(Indirection(dictKey=key), curObjRef) objRef = ContainerRef(Indirection(dictKey=key), parentObjRef)
yield None yield None
if isContainer: if hasLength:
for i in self._nameContainerGen(attr, objRef): for i in self._addContainerGen(attr, objRef):
yield None yield None
if notDeadEnd and nextObjRef is None: if notDeadEnd:
if random.randrange(numKeysLeft) == 0: self._addDiscoveredStartRef(attr, objRef)
nextObjRef = objRef if curObjRef is None and random.randrange(numKeysLeft) == 0:
numKeysLeft -= 1 curObjRef = objRef
if nextObjRef is not None:
self._curObjRef = nextObjRef
del key del key
del attr del attr
continue continue
if type(curObj) is not types.FileType:
try: try:
itr = iter(curObj) childNames = dir(curObj)
except: except:
pass pass
else: else:
try: try:
index = 0 index = -1
attrs = [] attrs = []
while 1: while 1:
yield None yield None
@ -418,72 +511,38 @@ class FindContainers(Job):
attrs.append(attr) attrs.append(attr)
# we will continue traversing the object graph via one attr, # we will continue traversing the object graph via one attr,
# choose it at random without taking a big chunk of CPU time # choose it at random without taking a big chunk of CPU time
numAttrsLeft = len(attrs) numAttrsLeft = len(attrs) + 1
nextObjRef = None
for attr in attrs: for attr in attrs:
yield None yield None
isContainer = self._isContainer(attr)
notDeadEnd = False
if nextObjRef is None:
notDeadEnd = not self._isDeadEnd(attr)
if isContainer or notDeadEnd:
objRef = ContainerRef(Indirection(evalStr='[%s]' % index), curObjRef)
yield None
if isContainer:
for i in self._nameContainerGen(attr, objRef):
yield None
if notDeadEnd and nextObjRef is None:
if random.randrange(numAttrsLeft) == 0:
nextObjRef = objRef
numAttrsLeft -= 1
index += 1 index += 1
if nextObjRef is not None: numAttrsLeft -= 1
self._curObjRef = nextObjRef hasLength = self._hasLength(attr)
notDeadEnd = False
if curObjRef is None:
notDeadEnd = not self._isDeadEnd(attr)
if hasLength or notDeadEnd:
objRef = ContainerRef(Indirection(evalStr='[%s]' % index),
parentObjRef)
yield None
if hasLength:
for i in self._addContainerGen(attr, objRef):
yield None
if notDeadEnd:
self._addDiscoveredStartRef(attr, objRef)
if curObjRef is None and random.randrange(numAttrsLeft) == 0:
curObjRef = objRef
del attr del attr
except StopIteration, e: except StopIteration, e:
pass pass
del itr del itr
continue continue
try:
childNames = dir(curObj)
except:
pass
else:
childName = None
child = None
# we will continue traversing the object graph via one child,
# choose it at random without taking a big chunk of CPU time
numChildrenLeft = len(childNames)
nextObjRef = None
for childName in childNames:
yield None
child = getattr(curObj, childName)
isContainer = self._isContainer(child)
notDeadEnd = False
if nextObjRef is None:
notDeadEnd = not self._isDeadEnd(child, childName)
if isContainer or notDeadEnd:
objRef = ContainerRef(Indirection(evalStr='.%s' % childName), curObjRef)
yield None
if isContainer:
for i in self._nameContainerGen(child, objRef):
yield None
if notDeadEnd and nextObjRef is None:
if random.randrange(numChildrenLeft) == 0:
nextObjRef = objRef
numChildrenLeft -= 1
if nextObjRef is not None:
self._curObjRef = nextObjRef
del childName
del child
continue
except Exception, e: except Exception, e:
print 'FindContainers job caught exception: %s' % e print 'FindContainers job caught exception: %s' % e
if __dev__: if __dev__:
#raise e #raise e
pass pass
yield Job.done yield Job.Done
class CheckContainers(Job): class CheckContainers(Job):
""" """
@ -510,60 +569,60 @@ class CheckContainers(Job):
self._leakDetector._index2containerId2len[self._index] = {} self._leakDetector._index2containerId2len[self._index] = {}
ids = self._leakDetector.getContainerIds() ids = self._leakDetector.getContainerIds()
# record the current len of each container # record the current len of each container
for id in ids: for objId in ids:
yield None yield None
try: try:
for result in self._leakDetector.getContainerByIdGen(id): for result in self._leakDetector.getContainerByIdGen(objId):
yield None yield None
container = result container = result
except Exception, e: except Exception, e:
# this container no longer exists # this container no longer exists
if self.notify.getDebug(): if self.notify.getDebug():
for contName in self._leakDetector.getContainerNameByIdGen(id): for contName in self._leakDetector.getContainerNameByIdGen(objId):
yield None yield None
self.notify.debug( self.notify.debug(
'%s no longer exists; caught exception in getContainerById (%s)' % ( '%s no longer exists; caught exception in getContainerById (%s)' % (
contName, e)) contName, e))
self._leakDetector.removeContainerById(id) self._leakDetector.removeContainerById(objId)
continue continue
if container is None: if container is None:
# this container no longer exists # this container no longer exists
if self.notify.getDebug(): if self.notify.getDebug():
for contName in self._leakDetector.getContainerNameByIdGen(id): for contName in self._leakDetector.getContainerNameByIdGen(objId):
yield None yield None
self.notify.debug('%s no longer exists; getContainerById returned None' % self.notify.debug('%s no longer exists; getContainerById returned None' %
contName) contName)
self._leakDetector.removeContainerById(id) self._leakDetector.removeContainerById(objId)
continue continue
try: try:
cLen = len(container) cLen = len(container)
except Exception, e: except Exception, e:
# this container no longer exists # this container no longer exists
if self.notify.getDebug(): if self.notify.getDebug():
for contName in self._leakDetector.getContainerNameByIdGen(id): for contName in self._leakDetector.getContainerNameByIdGen(objId):
yield None yield None
self.notify.debug( self.notify.debug(
'%s is no longer a container, it is now %s (%s)' % '%s is no longer a container, it is now %s (%s)' %
(contName, safeRepr(container), e)) (contName, safeRepr(container), e))
self._leakDetector.removeContainerById(id) self._leakDetector.removeContainerById(objId)
continue continue
self._leakDetector._index2containerId2len[self._index][id] = cLen self._leakDetector._index2containerId2len[self._index][objId] = cLen
# compare the current len of each container to past lens # compare the current len of each container to past lens
if self._index > 0: if self._index > 0:
idx2id2len = self._leakDetector._index2containerId2len idx2id2len = self._leakDetector._index2containerId2len
for id in idx2id2len[self._index]: for objId in idx2id2len[self._index]:
yield None yield None
if id in idx2id2len[self._index-1]: if objId in idx2id2len[self._index-1]:
diff = idx2id2len[self._index][id] - idx2id2len[self._index-1][id] diff = idx2id2len[self._index][objId] - idx2id2len[self._index-1][objId]
if diff > 0: if diff > 0:
if diff > idx2id2len[self._index-1][id]: if diff > idx2id2len[self._index-1][objId]:
minutes = (self._leakDetector._index2delay[self._index] - minutes = (self._leakDetector._index2delay[self._index] -
self._leakDetector._index2delay[self._index-1]) / 60. self._leakDetector._index2delay[self._index-1]) / 60.
name = self._leakDetector.getContainerNameById(id) name = self._leakDetector.getContainerNameById(objId)
if idx2id2len[self._index-1][id] != 0: if idx2id2len[self._index-1][objId] != 0:
percent = 100. * (float(diff) / float(idx2id2len[self._index-1][id])) percent = 100. * (float(diff) / float(idx2id2len[self._index-1][objId]))
try: try:
for container in self._leakDetector.getContainerByIdGen(id): for container in self._leakDetector.getContainerByIdGen(objId):
yield None yield None
except: except:
# TODO # TODO
@ -571,19 +630,19 @@ class CheckContainers(Job):
else: else:
self.notify.warning( self.notify.warning(
'%s (%s) grew %.2f%% in %.2f minutes (%s items at last measurement, current contents: %s)' % ( '%s (%s) grew %.2f%% in %.2f minutes (%s items at last measurement, current contents: %s)' % (
name, itype(container), percent, minutes, idx2id2len[self._index][id], name, itype(container), percent, minutes, idx2id2len[self._index][objId],
fastRepr(container, maxLen=CheckContainers.ReprItems))) fastRepr(container, maxLen=CheckContainers.ReprItems)))
yield None yield None
if (self._index > 2 and if (self._index > 2 and
id in idx2id2len[self._index-2] and objId in idx2id2len[self._index-2] and
id in idx2id2len[self._index-3]): objId in idx2id2len[self._index-3]):
diff2 = idx2id2len[self._index-1][id] - idx2id2len[self._index-2][id] diff2 = idx2id2len[self._index-1][objId] - idx2id2len[self._index-2][objId]
diff3 = idx2id2len[self._index-2][id] - idx2id2len[self._index-3][id] diff3 = idx2id2len[self._index-2][objId] - idx2id2len[self._index-3][objId]
if self._index <= 4: if self._index <= 4:
if diff > 0 and diff2 > 0 and diff3 > 0: if diff > 0 and diff2 > 0 and diff3 > 0:
name = self._leakDetector.getContainerNameById(id) name = self._leakDetector.getContainerNameById(objId)
try: try:
for container in self._leakDetector.getContainerByIdGen(id): for container in self._leakDetector.getContainerByIdGen(objId):
yield None yield None
except: except:
# TODO # TODO
@ -591,20 +650,20 @@ class CheckContainers(Job):
else: else:
msg = ('%s (%s) consistently increased in size over the last ' msg = ('%s (%s) consistently increased in size over the last '
'3 periods (%s items at last measurement, current contents: %s)' % '3 periods (%s items at last measurement, current contents: %s)' %
(name, itype(container), idx2id2len[self._index][id], (name, itype(container), idx2id2len[self._index][objId],
fastRepr(container, maxLen=CheckContainers.ReprItems))) fastRepr(container, maxLen=CheckContainers.ReprItems)))
self.notify.warning(msg) self.notify.warning(msg)
yield None yield None
elif (id in idx2id2len[self._index-4] and elif (objId in idx2id2len[self._index-4] and
id in idx2id2len[self._index-5]): objId in idx2id2len[self._index-5]):
# if size has consistently increased over the last 5 checks, # if size has consistently increased over the last 5 checks,
# send out a warning # send out a warning
diff4 = idx2id2len[self._index-3][id] - idx2id2len[self._index-4][id] diff4 = idx2id2len[self._index-3][objId] - idx2id2len[self._index-4][objId]
diff5 = idx2id2len[self._index-4][id] - idx2id2len[self._index-5][id] diff5 = idx2id2len[self._index-4][objId] - idx2id2len[self._index-5][objId]
if diff > 0 and diff2 > 0 and diff3 > 0 and diff4 > 0 and diff5 > 0: if diff > 0 and diff2 > 0 and diff3 > 0 and diff4 > 0 and diff5 > 0:
name = self._leakDetector.getContainerNameById(id) name = self._leakDetector.getContainerNameById(objId)
try: try:
for container in self._leakDetector.getContainerByIdGen(id): for container in self._leakDetector.getContainerByIdGen(objId):
yield None yield None
except: except:
# TODO # TODO
@ -612,7 +671,7 @@ class CheckContainers(Job):
else: else:
msg = ('%s (%s) consistently increased in size over the last ' msg = ('%s (%s) consistently increased in size over the last '
'5 periods (%s items at last measurement, current contents: %s)' % '5 periods (%s items at last measurement, current contents: %s)' %
(name, itype(container), idx2id2len[self._index][id], (name, itype(container), idx2id2len[self._index][objId],
fastRepr(container, maxLen=CheckContainers.ReprItems))) fastRepr(container, maxLen=CheckContainers.ReprItems)))
self.notify.warning(msg) self.notify.warning(msg)
self.notify.info('sending notification...') self.notify.info('sending notification...')
@ -649,12 +708,31 @@ class PruneContainerRefs(Job):
for id in ids: for id in ids:
yield None yield None
try: try:
for result in self._leakDetector.getContainerByIdGen(id): for container in self._leakDetector.getContainerByIdGen(id):
yield None yield None
container = result
except: except:
# reference is invalid, remove it # reference is invalid, remove it
self._leakDetector.removeContainerById(id) self._leakDetector.removeContainerById(id)
_id2baseStartRef = self._leakDetector._findContainersJob._id2baseStartRef
ids = _id2baseStartRef.keys()
for id in ids:
yield None
try:
for container in _id2baseStartRef[id].getContainer():
yield None
except:
# reference is invalid, remove it
del _id2baseStartRef[id]
_id2discoveredStartRef = self._leakDetector._findContainersJob._id2discoveredStartRef
ids = _id2discoveredStartRef.keys()
for id in ids:
yield None
try:
for container in _id2discoveredStartRef[id].getContainer():
yield None
except:
# reference is invalid, remove it
del _id2discoveredStartRef[id]
except Exception, e: except Exception, e:
print 'PruneContainerRefs job caught exception: %s' % e print 'PruneContainerRefs job caught exception: %s' % e
if __dev__: if __dev__: