CRDataCache.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. from direct.distributed.CachedDOData import CachedDOData
  2. from panda3d.core import ConfigVariableInt
  3. __all__ = ["CRDataCache"]
  4. class CRDataCache:
  5. # Stores cached data for DistributedObjects between instantiations on the client
  6. def __init__(self):
  7. self._doId2name2data = {}
  8. # maximum # of objects we will cache data for
  9. self._size = ConfigVariableInt('crdatacache-size', 10).getValue()
  10. assert self._size > 0
  11. # used to preserve the cache size
  12. self._junkIndex = 0
  13. def destroy(self):
  14. del self._doId2name2data
  15. def setCachedData(self, doId, name, data):
  16. # stores a set of named data for a DistributedObject
  17. assert isinstance(data, CachedDOData)
  18. if len(self._doId2name2data) >= self._size:
  19. # cache is full, throw out a random doId's data
  20. if self._junkIndex >= len(self._doId2name2data):
  21. self._junkIndex = 0
  22. junkDoId = list(self._doId2name2data.keys())[self._junkIndex]
  23. self._junkIndex += 1
  24. for name in self._doId2name2data[junkDoId]:
  25. self._doId2name2data[junkDoId][name].flush()
  26. del self._doId2name2data[junkDoId]
  27. self._doId2name2data.setdefault(doId, {})
  28. cachedData = self._doId2name2data[doId].get(name)
  29. if cachedData:
  30. cachedData.flush()
  31. cachedData.destroy()
  32. self._doId2name2data[doId][name] = data
  33. def hasCachedData(self, doId):
  34. return doId in self._doId2name2data
  35. def popCachedData(self, doId):
  36. # retrieves all cached data for a DistributedObject and removes it from the cache
  37. data = self._doId2name2data[doId]
  38. del self._doId2name2data[doId]
  39. return data
  40. def flush(self):
  41. # get rid of all cached data
  42. for doId in self._doId2name2data:
  43. for name in self._doId2name2data[doId]:
  44. self._doId2name2data[doId][name].flush()
  45. self._doId2name2data = {}
  46. if __debug__:
  47. def _startMemLeakCheck(self):
  48. self._len = len(self._doId2name2data)
  49. def _stopMemLeakCheck(self):
  50. del self._len
  51. def _checkMemLeaks(self):
  52. assert self._len == len(self._doId2name2data)
  53. if __debug__:
  54. class TestCachedData(CachedDOData):
  55. def __init__(self):
  56. CachedDOData.__init__(self)
  57. self._destroyed = False
  58. self._flushed = False
  59. def destroy(self):
  60. CachedDOData.destroy(self)
  61. self._destroyed = True
  62. def flush(self):
  63. CachedDOData.flush(self)
  64. self._flushed = True
  65. dc = CRDataCache()
  66. dc._startMemLeakCheck()
  67. cd = CachedDOData()
  68. cd.foo = 34
  69. dc.setCachedData(1, 'testCachedData', cd)
  70. del cd
  71. cd = CachedDOData()
  72. cd.bar = 45
  73. dc.setCachedData(1, 'testCachedData2', cd)
  74. del cd
  75. assert dc.hasCachedData(1)
  76. assert dc.hasCachedData(1)
  77. assert not dc.hasCachedData(2)
  78. # data is dict of dataName->data
  79. data = dc.popCachedData(1)
  80. assert len(data) == 2
  81. assert 'testCachedData' in data
  82. assert 'testCachedData2' in data
  83. assert data['testCachedData'].foo == 34
  84. assert data['testCachedData2'].bar == 45
  85. for cd in data.values():
  86. cd.flush()
  87. del data
  88. dc._checkMemLeaks()
  89. cd = CachedDOData()
  90. cd.bar = 1234
  91. dc.setCachedData(43, 'testCachedData2', cd)
  92. del cd
  93. assert dc.hasCachedData(43)
  94. dc.flush()
  95. dc._checkMemLeaks()
  96. dc._stopMemLeakCheck()
  97. dc.destroy()
  98. del dc