CRDataCache.py 3.5 KB

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