Fixed flush protection for instances, memory is successfully made available on an idmapper flush now.
This commit is contained in:
parent
4b8ed234fd
commit
58af67bdf2
6 changed files with 47 additions and 35 deletions
|
|
@ -14,6 +14,7 @@ See CmdHandler for practical examples on how to apply cmdsets
|
||||||
together to create interesting in-game effects.
|
together to create interesting in-game effects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from weakref import WeakKeyDictionary
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from src.utils.utils import inherits_from, is_iter
|
from src.utils.utils import inherits_from, is_iter
|
||||||
__all__ = ("CmdSet",)
|
__all__ = ("CmdSet",)
|
||||||
|
|
@ -159,7 +160,7 @@ class CmdSet(object):
|
||||||
|
|
||||||
# initialize system
|
# initialize system
|
||||||
self.at_cmdset_creation()
|
self.at_cmdset_creation()
|
||||||
self._contains_cache = {}
|
self._contains_cache = WeakKeyDictionary()#{}
|
||||||
|
|
||||||
# Priority-sensitive merge operations for cmdsets
|
# Priority-sensitive merge operations for cmdsets
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -686,6 +686,7 @@ class CmdServerLoad(MuxCommand):
|
||||||
if "mem" in self.switches:
|
if "mem" in self.switches:
|
||||||
caller.msg("Memory usage: RMEM: {w%g{n MB (%g%%), VMEM (res+swap+cache): {w%g{n MB." % (rmem, pmem, vmem))
|
caller.msg("Memory usage: RMEM: {w%g{n MB (%g%%), VMEM (res+swap+cache): {w%g{n MB." % (rmem, pmem, vmem))
|
||||||
return
|
return
|
||||||
|
|
||||||
if "flushmem" in self.switches:
|
if "flushmem" in self.switches:
|
||||||
caller.msg("Flushed object idmapper cache. Python garbage collector recovered memory from %i objects." % _idmapper.flush_cache())
|
caller.msg("Flushed object idmapper cache. Python garbage collector recovered memory from %i objects." % _idmapper.flush_cache())
|
||||||
return
|
return
|
||||||
|
|
@ -712,29 +713,26 @@ class CmdServerLoad(MuxCommand):
|
||||||
# because it lacks sys.getsizeof
|
# because it lacks sys.getsizeof
|
||||||
|
|
||||||
# object cache size
|
# object cache size
|
||||||
cachedict = _idmapper.cache_size()
|
total_num, total_size, cachedict = _idmapper.cache_size()
|
||||||
totcache = cachedict["_total"]
|
|
||||||
sorted_cache = sorted([(key, tup[0], tup[1]) for key, tup in cachedict.items() if key !="_total" and tup[0] > 0],
|
sorted_cache = sorted([(key, tup[0], tup[1]) for key, tup in cachedict.items() if key !="_total" and tup[0] > 0],
|
||||||
key=lambda tup: tup[2], reverse=True)
|
key=lambda tup: tup[2], reverse=True)
|
||||||
memtable = prettytable.PrettyTable(["entity name",
|
memtable = prettytable.PrettyTable(["entity name",
|
||||||
"number",
|
"number",
|
||||||
"cache (MB)",
|
|
||||||
"idmapper %%"])
|
"idmapper %%"])
|
||||||
memtable.align = 'l'
|
memtable.align = 'l'
|
||||||
for tup in sorted_cache:
|
for tup in sorted_cache:
|
||||||
memtable.add_row([tup[0],
|
memtable.add_row([tup[0],
|
||||||
"%i" % tup[1],
|
"%i" % tup[1],
|
||||||
"%5.2f" % tup[2],
|
"%.2f" % (float(tup[1] / 1.0*total_num) * 100)])
|
||||||
"%.2f" % (float(tup[2] / totcache[1]) * 100)])
|
|
||||||
|
|
||||||
# get sizes of other caches
|
# get sizes of other caches
|
||||||
attr_cache_info, prop_cache_info = get_cache_sizes()
|
#attr_cache_info, prop_cache_info = get_cache_sizes()
|
||||||
string += "\n{w Entity idmapper cache usage:{n %5.2f MB (%i items)\n%s" % (totcache[1], totcache[0], memtable)
|
string += "\n{w Entity idmapper cache:{n %i items\n%s" % (total_num, memtable)
|
||||||
#string += "\n{w On-entity Attribute cache usage:{n %5.2f MB (%i attrs)" % (attr_cache_info[1], attr_cache_info[0])
|
#string += "\n{w On-entity Attribute cache usage:{n %5.2f MB (%i attrs)" % (attr_cache_info[1], attr_cache_info[0])
|
||||||
#string += "\n{w On-entity Property cache usage:{n %5.2f MB (%i props)" % (prop_cache_info[1], prop_cache_info[0])
|
#string += "\n{w On-entity Property cache usage:{n %5.2f MB (%i props)" % (prop_cache_info[1], prop_cache_info[0])
|
||||||
base_mem = vmem - totcache[1] - attr_cache_info[1] - prop_cache_info[1]
|
#base_mem = vmem - total_size - attr_cache_info[1] - prop_cache_info[1]
|
||||||
#string += "\n{w Base Server usage (virtmem-idmapper-attrcache-propcache):{n %5.2f MB" % base_mem
|
#string += "\n{w Base Server usage (virtmem-idmapper-attrcache-propcache):{n %5.2f MB" % base_mem
|
||||||
string += "\n{w Base Server usage (virtmem - cache):{n %5.2f MB" % base_mem
|
#string += "\n{w Base Server usage (virtmem - cache):{n %5.2f MB" % base_mem
|
||||||
|
|
||||||
caller.msg(string)
|
caller.msg(string)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1088,7 +1088,7 @@ class Exit(Object):
|
||||||
if self.ndb.exit_reset or not self.cmdset.has_cmdset("_exitset", must_be_default=True):
|
if self.ndb.exit_reset or not self.cmdset.has_cmdset("_exitset", must_be_default=True):
|
||||||
# we are resetting, or no exit-cmdset was set. Create one dynamically.
|
# we are resetting, or no exit-cmdset was set. Create one dynamically.
|
||||||
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
|
self.cmdset.add_default(self.create_exit_cmdset(self.dbobj), permanent=False)
|
||||||
self.ndb.exit_reset = False
|
del self.ndb.exit_reset
|
||||||
|
|
||||||
# this and other hooks are what usually can be modified safely.
|
# this and other hooks are what usually can be modified safely.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -467,6 +467,7 @@ class NAttributeHandler(object):
|
||||||
def add(self, key, value):
|
def add(self, key, value):
|
||||||
"Add new key and value"
|
"Add new key and value"
|
||||||
self._store[key] = value
|
self._store[key] = value
|
||||||
|
print "set_recache_protection:", self.obj.key, key
|
||||||
self.obj.set_recache_protection()
|
self.obj.set_recache_protection()
|
||||||
|
|
||||||
def remove(self, key):
|
def remove(self, key):
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ def c_digs(client):
|
||||||
exitname1 = EXIT_TEMPLATE % client.counter()
|
exitname1 = EXIT_TEMPLATE % client.counter()
|
||||||
exitname2 = EXIT_TEMPLATE % client.counter()
|
exitname2 = EXIT_TEMPLATE % client.counter()
|
||||||
client.exits.extend([exitname1, exitname2])
|
client.exits.extend([exitname1, exitname2])
|
||||||
cmd = '@dig %s = %s, %s' % (roomname, exitname1, exitname2)
|
cmd = '@dig/tel %s = %s, %s' % (roomname, exitname1, exitname2)
|
||||||
return cmd, "digs ..."
|
return cmd, "digs ..."
|
||||||
|
|
||||||
def c_creates_obj(client):
|
def c_creates_obj(client):
|
||||||
|
|
@ -199,11 +199,17 @@ def c_moves(client):
|
||||||
# (0.1, c_help),
|
# (0.1, c_help),
|
||||||
# (0.4, c_moves))
|
# (0.4, c_moves))
|
||||||
## "socializing heavy builder" definition
|
## "socializing heavy builder" definition
|
||||||
|
#ACTIONS = (c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (0.1, c_socialize),
|
||||||
|
# (0.1, c_looks),
|
||||||
|
# (0.2, c_help),
|
||||||
|
# (0.1, c_creates_obj),
|
||||||
|
# (0.2, c_digs),
|
||||||
|
# (0.3, c_moves))
|
||||||
|
## "heavy digger memory tester" definition
|
||||||
ACTIONS = (c_login,
|
ACTIONS = (c_login,
|
||||||
c_logout,
|
c_logout,
|
||||||
#(0.1, c_socialize),
|
|
||||||
(0.1, c_looks),
|
(0.1, c_looks),
|
||||||
(0.2, c_help),
|
(0.1, c_creates_obj),
|
||||||
(0.2, c_creates_obj),
|
(0.8, c_digs))
|
||||||
(0.2, c_digs),
|
|
||||||
(0.3, c_moves))
|
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,10 @@ class SharedMemoryModel(Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
#def __init__(cls, *args, **kwargs):
|
||||||
|
# super(SharedMemoryModel, cls).__init__(*args, **kwargs)
|
||||||
|
# cls._idmapper_recache_protection = False
|
||||||
|
|
||||||
def _get_cache_key(cls, args, kwargs):
|
def _get_cache_key(cls, args, kwargs):
|
||||||
"""
|
"""
|
||||||
This method is used by the caching subsystem to infer the PK value from the constructor arguments.
|
This method is used by the caching subsystem to infer the PK value from the constructor arguments.
|
||||||
|
|
@ -238,11 +242,6 @@ class SharedMemoryModel(Model):
|
||||||
pass
|
pass
|
||||||
_flush_cached_by_key = classmethod(_flush_cached_by_key)
|
_flush_cached_by_key = classmethod(_flush_cached_by_key)
|
||||||
|
|
||||||
def set_recache_protection(cls, mode=True):
|
|
||||||
"set if this instance should be allowed to be recached."
|
|
||||||
cls._idmapper_recache_protection = bool(mode)
|
|
||||||
set_recache_protection = classmethod(set_recache_protection)
|
|
||||||
|
|
||||||
def flush_cached_instance(cls, instance, force=True):
|
def flush_cached_instance(cls, instance, force=True):
|
||||||
"""
|
"""
|
||||||
Method to flush an instance from the cache. The instance will
|
Method to flush an instance from the cache. The instance will
|
||||||
|
|
@ -254,6 +253,12 @@ class SharedMemoryModel(Model):
|
||||||
cls._flush_cached_by_key(instance._get_pk_val(), force=force)
|
cls._flush_cached_by_key(instance._get_pk_val(), force=force)
|
||||||
flush_cached_instance = classmethod(flush_cached_instance)
|
flush_cached_instance = classmethod(flush_cached_instance)
|
||||||
|
|
||||||
|
# per-instance methods
|
||||||
|
|
||||||
|
def set_recache_protection(cls, mode=True):
|
||||||
|
"set if this instance should be allowed to be recached."
|
||||||
|
cls._idmapper_recache_protection = bool(mode)
|
||||||
|
|
||||||
def flush_instance_cache(cls, force=False):
|
def flush_instance_cache(cls, force=False):
|
||||||
"""
|
"""
|
||||||
This will clean safe objects from the cache. Use force
|
This will clean safe objects from the cache. Use force
|
||||||
|
|
@ -352,29 +357,30 @@ post_save.connect(update_cached_instance)
|
||||||
|
|
||||||
def cache_size(mb=True):
|
def cache_size(mb=True):
|
||||||
"""
|
"""
|
||||||
Returns a dictionary with estimates of the
|
Calculate statistics about the cache
|
||||||
cache size of each subclass.
|
|
||||||
|
|
||||||
mb - return the result in MB.
|
mb - return the result in MB.
|
||||||
|
Returns
|
||||||
|
total_num, total_size, {objclass:(total_num, total_size)}
|
||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
sizedict = {"_total": [0, 0]}
|
totals = [0, 0] # totalnum, totalsize
|
||||||
|
sizedict = {}
|
||||||
def getsize(model):
|
def getsize(model):
|
||||||
instances = model.get_all_cached_instances()
|
instances = model.get_all_cached_instances()
|
||||||
linst = len(instances)
|
num_inst = len(instances)
|
||||||
size = sum([sys.getsizeof(o) for o in instances])
|
size = sum(sys.getsizeof(o) for o in instances)
|
||||||
size = (mb and size/1024.0) or size
|
size = size / 1000.0 if mb else size
|
||||||
return (linst, size)
|
return num_inst, size
|
||||||
def get_recurse(submodels):
|
def get_recurse(submodels):
|
||||||
for submodel in submodels:
|
for submodel in submodels:
|
||||||
subclasses = submodel.__subclasses__()
|
subclasses = submodel.__subclasses__()
|
||||||
if not subclasses:
|
if not subclasses:
|
||||||
tup = getsize(submodel)
|
num_inst, size = getsize(submodel)
|
||||||
sizedict["_total"][0] += tup[0]
|
totals[0] += num_inst
|
||||||
sizedict["_total"][1] += tup[1]
|
totals[1] += size
|
||||||
sizedict[submodel.__name__] = tup
|
sizedict[submodel.__name__] = (num_inst, size)
|
||||||
else:
|
else:
|
||||||
get_recurse(subclasses)
|
get_recurse(subclasses)
|
||||||
get_recurse(SharedMemoryModel.__subclasses__())
|
get_recurse(SharedMemoryModel.__subclasses__())
|
||||||
sizedict["_total"] = tuple(sizedict["_total"])
|
return totals[0], totals[1], sizedict
|
||||||
return sizedict
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue