forked from panda3d/panda3d
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCRCache.py
More file actions
137 lines (121 loc) · 4.88 KB
/
CRCache.py
File metadata and controls
137 lines (121 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
"""CRCache module: contains the CRCache class"""
from direct.directnotify import DirectNotifyGlobal
from . import DistributedObject
class CRCache:
notify = DirectNotifyGlobal.directNotify.newCategory("CRCache")
def __init__(self, maxCacheItems=10):
self.maxCacheItems = maxCacheItems
self.storedCacheItems = maxCacheItems
self.dict = {}
self.fifo = []
def isEmpty(self):
return len(self.fifo) == 0
def flush(self):
"""
Delete each item in the cache then clear all references to them
"""
assert self.checkCache()
CRCache.notify.debug("Flushing the cache")
# NOTE: delayDeleted objects should no longer get into the cache in the first place
# give objects a chance to clean themselves up before checking for DelayDelete leaks
messenger.send('clientCleanup')
# some of these objects might be holding delayDeletes on others
# track each object that is delayDeleted after it gets its chance to delete,
# and check them after all objects have had a chance to delete
delayDeleted = []
for distObj in self.dict.values():
distObj.deleteOrDelay()
if distObj.getDelayDeleteCount() != 0:
delayDeleted.append(distObj)
if distObj.getDelayDeleteCount() <= 0:
# make sure we're not leaking
distObj.detectLeaks()
# now that all objects have had a chance to delete, are there any objects left
# that are still delayDeleted?
delayDeleteLeaks = []
for distObj in delayDeleted:
if distObj.getDelayDeleteCount() != 0:
delayDeleteLeaks.append(distObj)
if len(delayDeleteLeaks):
s = 'CRCache.flush:'
for obj in delayDeleteLeaks:
s += ('\n could not delete %s (%s), delayDeletes=%s' %
(safeRepr(obj), itype(obj), obj.getDelayDeleteNames()))
self.notify.error(s)
# Null out all references to the objects so they will get gcd
self.dict = {}
self.fifo = []
def cache(self, distObj):
# Only distributed objects are allowed in the cache
assert isinstance(distObj, DistributedObject.DistributedObject)
assert self.checkCache()
# Get the doId
doId = distObj.getDoId()
# Error check
success = False
if doId in self.dict:
CRCache.notify.warning("Double cache attempted for distObj "
+ str(doId))
else:
# Call disable on the distObj
distObj.disableAndAnnounce()
# Put the distObj in the fifo and the dict
self.fifo.append(distObj)
self.dict[doId] = distObj
success = True
if len(self.fifo) > self.maxCacheItems:
# if the cache is full, pop the oldest item
oldestDistObj = self.fifo.pop(0)
# and remove it from the dictionary
del(self.dict[oldestDistObj.getDoId()])
# and delete it
oldestDistObj.deleteOrDelay()
if oldestDistObj.getDelayDeleteCount() <= 0:
# make sure we're not leaking
oldestDistObj.detectLeaks()
# Make sure that the fifo and the dictionary are sane
assert len(self.dict) == len(self.fifo)
return success
def retrieve(self, doId):
assert self.checkCache()
if doId in self.dict:
# Find the object
distObj = self.dict[doId]
# Remove it from the dictionary
del(self.dict[doId])
# Remove it from the fifo
self.fifo.remove(distObj)
# return the distObj
return distObj
else:
# If you can't find it, return None
return None
def contains(self, doId):
return doId in self.dict
def delete(self, doId):
assert self.checkCache()
assert doId in self.dict
# Look it up
distObj = self.dict[doId]
# Remove it from the dict and fifo
del(self.dict[doId])
self.fifo.remove(distObj)
# and delete it
distObj.deleteOrDelay()
if distObj.getDelayDeleteCount() <= 0:
# make sure we're not leaking
distObj.detectLeaks()
def checkCache(self):
# For debugging; this verifies that the cache is sensible and
# returns true if so.
from panda3d.core import NodePath
for obj in self.dict.values():
if isinstance(obj, NodePath):
assert not obj.isEmpty() and obj.getTopNode() != render.node()
return 1
def turnOff(self):
self.flush()
self.storedMaxCache = self.maxCacheItems
self.maxCacheItems = 0
def turnOn(self):
self.maxCacheItems = self.storedMaxCache