mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 17:35:34 -04:00
added CRDataCache
This commit is contained in:
parent
91147411ee
commit
ef0ba78f1d
113
direct/src/distributed/CRDataCache.py
Executable file
113
direct/src/distributed/CRDataCache.py
Executable file
@ -0,0 +1,113 @@
|
||||
from direct.distributed.CachedDOData import CachedDOData
|
||||
|
||||
class CRDataCache:
|
||||
# Stores cached data for DistributedObjects between instantiations on the client
|
||||
|
||||
def __init__(self):
|
||||
self._doId2name2data = {}
|
||||
# maximum # of objects we will cache data for
|
||||
self._size = config.GetInt('crdatacache-size', 10)
|
||||
assert self._size > 0
|
||||
# used to preserve the cache size
|
||||
self._junkIndex = 0
|
||||
|
||||
def destroy(self):
|
||||
del self._doId2name2data
|
||||
|
||||
def setCachedData(self, doId, name, data):
|
||||
# stores a set of named data for a DistributedObject
|
||||
assert isinstance(data, CachedDOData)
|
||||
if len(self._doId2name2data) >= self._size:
|
||||
# cache is full, throw out a random doId's data
|
||||
if self._junkIndex >= len(self._doId2name2data):
|
||||
self._junkIndex = 0
|
||||
junkDoId = self._doId2name2data.keys()[self._junkIndex]
|
||||
self._junkIndex += 1
|
||||
for name in self._doId2name2data[junkDoId]:
|
||||
self._doId2name2data[junkDoId][name].flush()
|
||||
del self._doId2name2data[junkDoId]
|
||||
|
||||
self._doId2name2data.setdefault(doId, {})
|
||||
cachedData = self._doId2name2data[doId].get(name)
|
||||
if cachedData:
|
||||
cachedData.flush()
|
||||
cachedData.destroy()
|
||||
self._doId2name2data[doId][name] = data
|
||||
|
||||
def hasCachedData(self, doId):
|
||||
return doId in self._doId2name2data
|
||||
|
||||
def popCachedData(self, doId):
|
||||
# retrieves all cached data for a DistributedObject and removes it from the cache
|
||||
data = self._doId2name2data[doId]
|
||||
del self._doId2name2data[doId]
|
||||
return data
|
||||
|
||||
def flush(self):
|
||||
# get rid of all cached data
|
||||
for doId in self._doId2name2data:
|
||||
for name in self._doId2name2data[doId]:
|
||||
self._doId2name2data[doId][name].flush()
|
||||
self._doId2name2data = {}
|
||||
|
||||
if __debug__:
|
||||
def _startMemLeakCheck(self):
|
||||
self._len = len(self._doId2name2data)
|
||||
|
||||
def _stopMemLeakCheck(self):
|
||||
del self._len
|
||||
|
||||
def _checkMemLeaks(self):
|
||||
assert self._len == len(self._doId2name2data)
|
||||
|
||||
if __debug__:
|
||||
class TestCachedData(CachedDOData):
|
||||
def __init__(self):
|
||||
CachedDOData.__init__(self)
|
||||
self._destroyed = False
|
||||
self._flushed = False
|
||||
def destroy(self):
|
||||
CachedDOData.destroy(self)
|
||||
self._destroyed = True
|
||||
def flush(self):
|
||||
CachedDOData.flush(self)
|
||||
self._flushed = True
|
||||
|
||||
dc = CRDataCache()
|
||||
dc._startMemLeakCheck()
|
||||
|
||||
cd = CachedDOData()
|
||||
cd.foo = 34
|
||||
dc.setCachedData(1, 'testCachedData', cd)
|
||||
del cd
|
||||
cd = CachedDOData()
|
||||
cd.bar = 45
|
||||
dc.setCachedData(1, 'testCachedData2', cd)
|
||||
del cd
|
||||
assert dc.hasCachedData(1)
|
||||
assert dc.hasCachedData(1)
|
||||
assert not dc.hasCachedData(2)
|
||||
# data is dict of dataName->data
|
||||
data = dc.popCachedData(1)
|
||||
assert len(data) == 2
|
||||
assert 'testCachedData' in data
|
||||
assert 'testCachedData2' in data
|
||||
assert data['testCachedData'].foo == 34
|
||||
assert data['testCachedData2'].bar == 45
|
||||
for cd in data.itervalues():
|
||||
cd.flush()
|
||||
del data
|
||||
dc._checkMemLeaks()
|
||||
|
||||
cd = CachedDOData()
|
||||
cd.bar = 1234
|
||||
dc.setCachedData(43, 'testCachedData2', cd)
|
||||
del cd
|
||||
assert dc.hasCachedData(43)
|
||||
dc.flush()
|
||||
dc._checkMemLeaks()
|
||||
|
||||
dc._stopMemLeakCheck()
|
||||
dc.destroy()
|
||||
del dc
|
||||
|
22
direct/src/distributed/CachedDOData.py
Executable file
22
direct/src/distributed/CachedDOData.py
Executable file
@ -0,0 +1,22 @@
|
||||
|
||||
class CachedDOData:
|
||||
# base class for objects that are used to store data in the CRDataCache
|
||||
#
|
||||
# stores a minimal set of cached data for DistributedObjects between instantiations
|
||||
|
||||
def __init__(self):
|
||||
# override and store cached data
|
||||
# this object now owns the data
|
||||
# ownership will either pass back to another instantion of the object,
|
||||
# or the data will be flushed
|
||||
pass
|
||||
|
||||
def destroy(self):
|
||||
# override and handle this object being destroyed
|
||||
# this is destruction of this object, not the cached data (see flush)
|
||||
pass
|
||||
|
||||
def flush(self):
|
||||
# override and destroy the cached data
|
||||
# cached data is typically created by the DistributedObject and destroyed here
|
||||
pass
|
@ -58,6 +58,7 @@ class ClientRepository(ClientRepositoryBase):
|
||||
obj.doId = id
|
||||
self.doId2do[id] = obj
|
||||
obj.generateInit()
|
||||
obj._retrieveCachedData()
|
||||
obj.generate()
|
||||
obj.announceGenerate()
|
||||
datagram = dclass.clientFormatGenerate(obj, id, zoneId, optionalFields)
|
||||
@ -201,6 +202,7 @@ class ClientRepository(ClientRepositoryBase):
|
||||
self.doId2do[doId] = distObj
|
||||
# Update the required fields
|
||||
distObj.generateInit() # Only called when constructed
|
||||
distObj._retrieveCachedData()
|
||||
distObj.generate()
|
||||
distObj.updateRequiredFields(dclass, di)
|
||||
# updateRequiredFields calls announceGenerate
|
||||
|
@ -3,6 +3,7 @@ from MsgTypes import *
|
||||
from direct.task import Task
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
import CRCache
|
||||
from direct.distributed.CRDataCache import CRDataCache
|
||||
from direct.distributed.ConnectionRepository import ConnectionRepository
|
||||
from direct.showbase import PythonUtil
|
||||
import ParentMgr
|
||||
@ -44,6 +45,7 @@ class ClientRepositoryBase(ConnectionRepository):
|
||||
|
||||
self.readDCFile(dcFileNames)
|
||||
self.cache=CRCache.CRCache()
|
||||
self.doDataCache = CRDataCache()
|
||||
self.cacheOwner=CRCache.CRCache()
|
||||
self.serverDelta = 0
|
||||
|
||||
@ -365,6 +367,7 @@ class ClientRepositoryBase(ConnectionRepository):
|
||||
self.doId2do[doId] = distObj
|
||||
# Update the required fields
|
||||
distObj.generateInit() # Only called when constructed
|
||||
distObj._retrieveCachedData()
|
||||
distObj.generate()
|
||||
distObj.setLocation(parentId, zoneId)
|
||||
distObj.updateRequiredFields(dclass, di)
|
||||
@ -412,6 +415,7 @@ class ClientRepositoryBase(ConnectionRepository):
|
||||
self.doId2do[doId] = distObj
|
||||
# Update the required fields
|
||||
distObj.generateInit() # Only called when constructed
|
||||
distObj._retrieveCachedData()
|
||||
distObj.generate()
|
||||
distObj.setLocation(parentId, zoneId)
|
||||
distObj.updateRequiredOtherFields(dclass, di)
|
||||
|
@ -154,6 +154,35 @@ class DistributedObject(DistributedObjectBase):
|
||||
def getNeverDisable(self):
|
||||
return self.neverDisable
|
||||
|
||||
def _retrieveCachedData(self):
|
||||
# once we know our doId, grab any data that might be stored in the data cache
|
||||
# from the last time we were on the client
|
||||
if self.cr.doDataCache.hasCachedData(self.doId):
|
||||
self._cachedData = self.cr.doDataCache.popCachedData(self.doId)
|
||||
|
||||
def setCachedData(self, name, data):
|
||||
assert type(name) == type('')
|
||||
# ownership of the data passes to the repository data cache
|
||||
self.cr.doDataCache.setCachedData(self.doId, name, data)
|
||||
|
||||
def hasCachedData(self, name):
|
||||
assert type(name) == type('')
|
||||
if not hasattr(self, '_cachedData'):
|
||||
return False
|
||||
return name in self._cachedData
|
||||
|
||||
def getCachedData(self, name):
|
||||
assert type(name) == type('')
|
||||
# ownership of the data passes to the caller of this method
|
||||
data = self._cachedData[name]
|
||||
del self._cachedData[name]
|
||||
return data
|
||||
|
||||
def flushCachedData(self, name):
|
||||
assert type(name) == type('')
|
||||
# call this to throw out cached data from a previous instantiation
|
||||
self._cachedData[name].flush()
|
||||
|
||||
def setCacheable(self, bool):
|
||||
assert bool == 1 or bool == 0
|
||||
self.cacheable = bool
|
||||
@ -272,6 +301,13 @@ class DistributedObject(DistributedObjectBase):
|
||||
# after this is called, the object is no longer a DistributedObject
|
||||
# but may still be used as a DelayDeleted object
|
||||
self.destroyDoStackTrace = StackTrace()
|
||||
# check for leftover cached data that was not retrieved or flushed by this object
|
||||
# this will catch typos in the data name in calls to get/setCachedData
|
||||
if hasattr(self, '_cachedData'):
|
||||
for name, cachedData in self._cachedData.iteritems():
|
||||
self.notify.warning('flushing unretrieved cached data: %s' % name)
|
||||
cachedData.flush()
|
||||
del self._cachedData
|
||||
self.cr = None
|
||||
self.dclass = None
|
||||
|
||||
|
@ -58,6 +58,7 @@ class OldClientRepository(ClientRepositoryBase):
|
||||
obj.doId = id
|
||||
self.doId2do[id] = obj
|
||||
obj.generateInit()
|
||||
obj._retrieveCachedData()
|
||||
obj.generate()
|
||||
obj.announceGenerate()
|
||||
datagram = dclass.clientFormatGenerate(obj, id, zoneId, optionalFields)
|
||||
|
Loading…
x
Reference in New Issue
Block a user