Added fix to object.contents cache as well as reworked the extent of cache hooks on location modification.

This commit is contained in:
Griatch 2013-10-21 21:17:32 +02:00
parent 07af616b67
commit 06a0bea8d6
11 changed files with 125 additions and 653 deletions

View file

@ -421,7 +421,6 @@ class CmdCreate(ObjManipCommand):
if 'drop' in self.switches:
if caller.location:
obj.home = caller.location
print "Doing the drop"
obj.move_to(caller.location, quiet=True)
if string:
caller.msg(string)

View file

@ -338,6 +338,7 @@ class ChannelManager(models.Manager):
ostring - the key or database id of the channel.
"""
channels = []
if not ostring: return channels
try:
# try an id match first
dbref = int(ostring.strip('#'))

View file

@ -174,7 +174,7 @@ class ObjectManager(TypedObjectManager):
excludeobj - one or more object keys to exclude from the match
"""
exclude_restriction = excludeobj and Q(pk__in=[_GA(obj, "in") for obj in make_iter(excludeobj)]) or Q()
exclude_restriction = Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q()
return self.filter(db_location=location).exclude(exclude_restriction)
@returns_typeclass_list

View file

@ -145,265 +145,14 @@ class ObjectDB(TypedObject):
_SA(self, "aliases", AliasHandler(self, category_prefix="object_"))
_SA(self, "nicks", NickHandler(self))
# make sure to sync the contents cache when initializing
_GA(self, "contents_update")()
#_GA(self, "contents_update")()
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the object in question).
## player property (wraps db_player)
##@property
#def __player_get(self):
# """
# Getter. Allows for value = self.player.
# We have to be careful here since Player is also
# a TypedObject, so as to not create a loop.
# """
# player = _GA(self, "db_player")
# #player = get_field_cache(self, "player")
# if player:
# try:
# return player.typeclass
# except Exception,e:
# print "player_get:", e
# return player
##@player.setter
#def __player_set(self, player):
# "Setter. Allows for self.player = value"
# if inherits_from(player, TypeClass):
# player = player.dbobj
# _SA(self, "db_player", player)
# _GA(self, "save")()
# #set_field_cache(self, "player", player)
# # we must set this here or superusers won't be able to
# # bypass lockchecks unless they start the game connected
# # to the character in question.
# self.locks.cache_lock_bypass(self)
##@player.deleter
#def __player_del(self):
# "Deleter. Allows for del self.player"
# _SA(self, "db_player", None)
# _GA(self, "save")()
# #del_field_cache(self, "player")
#player = property(__player_get, __player_set, __player_del)
#sessid property (wraps db_sessid)
#@property
#def __sessid_get(self):
# """
# Getter. Allows for value = self.sessid. Since sessid
# is directly related to self.player, we cannot have
# a sessid without a player being connected (but the
# opposite could be true).
# """
# return _GA(self, "db_sessid")
# #if not get_field_cache(self, "sessid"):
# # del_field_cache(self, "sessid")
# #return get_field_cache(self, "sessid")
##@sessid.setter
#def __sessid_set(self, sessid):
# "Setter. Allows for self.player = value"
# _SA(self, "db_sessid", sessid)
# _GA(self, "save")()
# #set_field_cache(self, "sessid", sessid)
##@sessid.deleter
#def __sessid_del(self):
# "Deleter. Allows for del self.player"
# _SA(self, "db_sessid", None)
# _GA(self, "save")()
# #del_field_cache(self, "sessid")
#sessid = property(__sessid_get, __sessid_set, __sessid_del)
def _at_db_player_save(self, new_value, old_value=None):
def _at_db_player_presave(self):
"""
This is called automatically just before a new player is saved.
This hook is called automatically just before the player field is saved.
"""
# we need to re-cache this for superusers to bypass.
self.locks.cache_lock_bypass(self)
return new_value
def _at_db_location_save(self, new_value, old_value=None):
"""
This is called automatically just before a new location is saved.
"""
loc = new_value
try:
old_loc = old_value
# recursive location check
def is_loc_loop(loc, depth=0):
"Recursively traverse the target location to make sure we are not in it."
if depth > 10: return
elif loc == self: raise RuntimeError
elif loc == None: raise RuntimeWarning # just to quickly get out
return is_loc_loop(_GA(loc, "db_location"), depth+1)
# check so we don't create a location loop - if so, RuntimeError will be raised.
try: is_loc_loop(loc)
except RuntimeWarning: pass
# update the contents of each location
if old_loc:
_GA(_GA(old_loc, "dbobj"), "contents_update")()
#print "after contents_update for old_loc:", old_loc.key, old_loc.contents
if loc:
_GA(_GA(loc, "dbobj"), "contents_update")()
#print "after contents_update for loc:", loc.key, loc.contents
return loc
except RuntimeError:
string = "Cannot set location, "
string += "%s.location = %s would create a location-loop." % (self.key, loc)
_GA(self, "msg")(_(string))
logger.log_trace(string)
raise RuntimeError(string)
except Exception, e:
string = "Cannot set location (%s): " % str(e)
string += "%s is not a valid location." % loc
_GA(self, "msg")(_(string))
logger.log_trace(string)
raise Exception(string)
## location property (wraps db_location)
##@property
#def __location_get(self):
# "Getter. Allows for value = self.location."
# loc = get_field_cache(self, "location")
# if loc:
# return _GA(loc, "typeclass")
# return None
##@location.setter
#def __location_set(self, location):
# "Setter. Allows for self.location = location"
# try:
# old_loc = _GA(self, "location")
# if ObjectDB.objects.dbref(location):
# # dbref search
# loc = ObjectDB.objects.dbref_search(location)
# loc = loc and _GA(loc, "dbobj")
# elif location and type(location) != ObjectDB:
# loc = _GA(location, "dbobj")
# else:
# loc = location
# # recursive location check
# def is_loc_loop(loc, depth=0):
# "Recursively traverse the target location to make sure we are not in it."
# if depth > 10: return
# elif loc == self: raise RuntimeError
# elif loc == None: raise RuntimeWarning # just to quickly get out
# return is_loc_loop(_GA(loc, "db_location"), depth+1)
# # check so we don't create a location loop - if so, RuntimeError will be raised.
# try: is_loc_loop(loc)
# except RuntimeWarning: pass
# # set the location
# set_field_cache(self, "location", loc)
# # update the contents of each location
# if old_loc:
# _GA(_GA(old_loc, "dbobj"), "contents_update")()
# if loc:
# _GA(loc, "contents_update")()
# except RuntimeError:
# string = "Cannot set location, "
# string += "%s.location = %s would create a location-loop." % (self.key, loc)
# _GA(self, "msg")(_(string))
# logger.log_trace(string)
# raise RuntimeError(string)
# except Exception, e:
# string = "Cannot set location (%s): " % str(e)
# string += "%s is not a valid location." % location
# _GA(self, "msg")(_(string))
# logger.log_trace(string)
# raise Exception(string)
##@location.deleter
#def __location_del(self):
# "Deleter. Allows for del self.location"
# _GA(self, "location").contents_update()
# _SA(self, "db_location", None)
# _GA(self, "save")()
# del_field_cache(self, "location")
#location = property(__location_get, __location_set, __location_del)
# home property (wraps db_home)
#@property
#def __home_get(self):
# "Getter. Allows for value = self.home"
# home = get_field_cache(self, "home")
# if home:
# return _GA(home, "typeclass")
# return None
##@home.setter
#def __home_set(self, home):
# "Setter. Allows for self.home = value"
# try:
# if home == None or type(home) == ObjectDB:
# hom = home
# elif ObjectDB.objects.dbref(home):
# hom = ObjectDB.objects.dbref_search(home)
# if hom and hasattr(hom,'dbobj'):
# hom = _GA(hom, "dbobj")
# else:
# hom = _GA(home, "dbobj")
# else:
# hom = _GA(home, "dbobj")
# set_field_cache(self, "home", hom)
# except Exception:
# string = "Cannot set home: "
# string += "%s is not a valid home."
# _GA(self, "msg")(_(string) % home)
# logger.log_trace(string)
# #raise
##@home.deleter
#def __home_del(self):
# "Deleter. Allows for del self.home."
# _SA(self, "db_home", None)
# _GA(self, "save")()
# del_field_cache(self, "home")
#home = property(__home_get, __home_set, __home_del)
# destination property (wraps db_destination)
#@property
#def __destination_get(self):
# "Getter. Allows for value = self.destination."
# dest = get_field_cache(self, "destination")
# if dest:
# return _GA(dest, "typeclass")
# return None
##@destination.setter
#def __destination_set(self, destination):
# "Setter. Allows for self.destination = destination"
# try:
# if destination == None or type(destination) == ObjectDB:
# # destination is None or a valid object
# dest = destination
# elif ObjectDB.objects.dbref(destination):
# # destination is a dbref; search
# dest = ObjectDB.objects.dbref_search(destination)
# if dest and _GA(self, "_hasattr")(dest,'dbobj'):
# dest = _GA(dest, "dbobj")
# else:
# dest = _GA(destination, "dbobj")
# else:
# dest = destination.dbobj
# set_field_cache(self, "destination", dest)
# except Exception:
# string = "Cannot set destination: "
# string += "%s is not a valid destination." % destination
# _GA(self, "msg")(string)
# logger.log_trace(string)
# raise
##@destination.deleter
#def __destination_del(self):
# "Deleter. Allows for del self.destination"
# _SA(self, "db_destination", None)
# _GA(self, "save")()
# del_field_cache(self, "destination")
#destination = property(__destination_get, __destination_set, __destination_del)
# cmdset_storage property. We use a custom wrapper to manage this. This also
# seems very sensitive to caching, so leaving it be for now. /Griatch
@ -434,7 +183,6 @@ class ObjectDB(TypedObject):
# ObjectDB class access methods/properties
#
#@property
def __sessions_get(self):
"""
@ -473,23 +221,11 @@ class ObjectDB(TypedObject):
exclude is one or more objects to not return
"""
contents = get_prop_cache(self, "_contents")
if contents == None:
# this is the case if this is the first call
contents = _GA(self, "contents_update")()
if exclude:
exclude = [obj.typeclass for obj in make_iter(exclude)]
return [obj for obj in contents if obj not in exclude]
else:
return contents
return ObjectDB.objects.get_contents(self, excludeobj=exclude)
return ObjectDB.objects.get_contents(self)
contents = property(contents_get)
def contents_update(self):
"Re-sync the contents cache"
contents = ObjectDB.objects.get_contents(self)
set_prop_cache(self, "_contents", contents)
return contents
#@property
def __exits_get(self):
"""
@ -972,6 +708,6 @@ class ObjectDB(TypedObject):
# Perform the deletion of the object
super(ObjectDB, self).delete()
# clear object's old location's content cache of this object
if old_loc:
_GA(old_loc.dbobj, "contents_update")()
#if old_loc:
# _GA(old_loc.dbobj, "contents_update")()
return True

View file

@ -117,29 +117,11 @@ class PlayerDB(TypedObject, AbstractUser):
_SA(self, "aliases", AliasHandler(self, category_prefix="player_"))
_SA(self, "nicks", NickHandler(self))
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# obj property (wraps db_obj)
#@property
def objs_get(self):
"Getter. Allows for value = self.obj"
return list(self.db_objs.all())
#@objs.setter
def objs_set(self, value):
"Setter. Allows for self.objs = value"
raise Exception("Use access methods to add new characters instead.")
#@obj.deleter
def objs_del(self):
"Deleter. Allows for del self.obj"
raise Exception("Use access methods to delete new characters instead.")
objs = property(objs_get, objs_set, objs_del)
characters = property(objs_get, objs_set, objs_del)
# alias to the objs property
def __characters_get(self): return self.objs
def __characters_set(self, value): self.objs = value
def __characters_del(self): raise Exception("Cannot delete name")
characters = property(__characters_get, __characters_set, __characters_del)
# cmdset_storage property
# This seems very sensitive to caching, so leaving it be for now /Griatch
@ -161,20 +143,6 @@ class PlayerDB(TypedObject, AbstractUser):
_GA(self, "save")()
cmdset_storage = property(cmdset_storage_get, cmdset_storage_set, cmdset_storage_del)
##@property
#def is_connected_get(self):
# "Getter. Allows for value = self.is_connected"
# return get_field_cache(self, "is_connected")
##@is_connected.setter
#def is_connected_set(self, value):
# "Setter. Allows for self.is_connected = value"
# set_field_cache(self, "is_connected", value)
##@is_connected.deleter
#def is_connected_del(self):
# "Deleter. Allows for del is_connected"
# set_field_cache(self, "is_connected", False)
#is_connected = property(is_connected_get, is_connected_set, is_connected_del)
class Meta:
"Define Django meta options"
verbose_name = "Player"
@ -190,35 +158,14 @@ class PlayerDB(TypedObject, AbstractUser):
def __unicode__(self):
return u"%s(player#%s)" % (_GA(self, "name"), _GA(self, "dbid"))
# name property (wraps self.user.username)
#@property
#def __name_get(self):
# "Getter. Allows for value = self.name"
# return self.username
# #name = get_prop_cache(self, "_name")
# #if not name:
# # name = _GA(self,"user").username
# # set_prop_cache(self, "_name", name)
# #return name
##@name.setter
#def __name_set(self, value):
# "Setter. Allows for player.name = newname"
# _SA(self, "username", value)
# #_GA(self, "user").username = value
# #_GA(self, "user").save()
# #set_prop_cache(self, "_name", value)
##@name.deleter
#def __name_del(self):
# "Deleter. Allows for del self.name"
# raise Exception("Player name cannot be deleted!")
def __username_get(self):
return _GA(self, "username")
def __username_set(self, value):
_SA(self, "username", value)
def __username_del(self):
_DA(self, "username", value)
# aliases
name = property(__username_get, __username_set, __username_del)
key = property(__username_get, __username_set, __username_del)

View file

@ -111,133 +111,6 @@ class ScriptDB(TypedObject):
_SA(self, "attributes", AttributeHandler(self))
#_SA(self, "aliases", AliasHandler(self, category_prefix="script_"))
# Wrapper properties to easily set database fields. These are
# @property decorators that allows to access these fields using
# normal python operations (without having to remember to save()
# etc). So e.g. a property 'attr' has a get/set/del decorator
# defined that allows the user to do self.attr = value,
# value = self.attr and del self.attr respectively (where self
# is the script in question).
# desc property (wraps db_desc)
#@property
#def __desc_get(self):
# "Getter. Allows for value = self.desc"
# return self.db_desc
##@desc.setter
#def __desc_set(self, value):
# "Setter. Allows for self.desc = value"
# self.db_desc = value
# self.save()
##@desc.deleter
#def __desc_del(self):
# "Deleter. Allows for del self.desc"
# self.db_desc = ""
# self.save()
#desc = property(__desc_get, __desc_set, __desc_del)
# obj property (wraps db_obj)
#@property
#def __obj_get(self):
# "Getter. Allows for value = self.obj"
# return self.db_obj
##@obj.setter
#def __obj_set(self, value):
# "Setter. Allows for self.obj = value"
# self.db_obj = value
# self.save()
##@obj.deleter
#def __obj_del(self):
# "Deleter. Allows for del self.obj"
# self.db_obj = None
# self.save()
#obj = property(__obj_get, __obj_set, __obj_del)
# interval property (wraps db_interval)
#@property
#def __interval_get(self):
# "Getter. Allows for value = self.interval"
# return self.db_interval
##@interval.setter
#def __interval_set(self, value):
# "Setter. Allows for self.interval = value"
# self.db_interval = int(value)
# self.save()
##@interval.deleter
#def __interval_del(self):
# "Deleter. Allows for del self.interval"
# self.db_interval = 0
# self.save()
#interval = property(__interval_get, __interval_set, __interval_del)
# start_delay property (wraps db_start_delay)
#@property
#def __start_delay_get(self):
# "Getter. Allows for value = self.start_delay"
# return self.db_start_delay
##@start_delay.setter
#def __start_delay_set(self, value):
# "Setter. Allows for self.start_delay = value"
# self.db_start_delay = value
# self.save()
##@start_delay.deleter
#def __start_delay_del(self):
# "Deleter. Allows for del self.start_delay"
# self.db_start_delay = False
# self.save()
#start_delay = property(__start_delay_get, __start_delay_set, __start_delay_del)
# repeats property (wraps db_repeats)
#@property
#def __repeats_get(self):
# "Getter. Allows for value = self.repeats"
# return self.db_repeats
##@repeats.setter
#def __repeats_set(self, value):
# "Setter. Allows for self.repeats = value"
# self.db_repeats = int(value)
# self.save()
##@repeats.deleter
#def __repeats_del(self):
# "Deleter. Allows for del self.repeats"
# self.db_repeats = 0
# self.save()
#repeats = property(__repeats_get, __repeats_set, __repeats_del)
# persistent property (wraps db_persistent)
#@property
#def __persistent_get(self):
# "Getter. Allows for value = self.persistent"
# return self.db_persistent
##@persistent.setter
#def __persistent_set(self, value):
# "Setter. Allows for self.persistent = value"
# self.db_persistent = value
# self.save()
##@persistent.deleter
#def __persistent_del(self):
# "Deleter. Allows for del self.persistent"
# self.db_persistent = False
# self.save()
#persistent = property(__persistent_get, __persistent_set, __persistent_del)
# is_active property (wraps db_is_active)
#@property
#def __is_active_get(self):
# "Getter. Allows for value = self.is_active"
# return self.db_is_active
##@is_active.setter
#def __is_active_set(self, value):
# "Setter. Allows for self.is_active = value"
# self.db_is_active = value
# self.save()
##@is_active.deleter
#def __is_active_del(self):
# "Deleter. Allows for del self.is_active"
# self.db_is_active = False
# self.save()
#is_active = property(__is_active_get, __is_active_set, __is_active_del)
#
#
# ScriptDB class properties

View file

@ -19,8 +19,6 @@ from src.utils import logger, is_pypy
from django.utils.translation import ugettext as _
__all__ = ["Script", "DoNothing", "CheckSessions", "ValidateScripts", "ValidateChannelHandler"]
if not is_pypy:
__all__.append("ClearAttributeCache")
_SESSIONS = None
_ATTRIBUTE_CACHE_MAXSIZE = settings.ATTRIBUTE_CACHE_MAXSIZE # attr-cache size in MB.
@ -451,19 +449,19 @@ class ValidateChannelHandler(Script):
#print "ValidateChannelHandler run."
channelhandler.CHANNELHANDLER.update()
class ClearAttributeCache(Script):
"Clear the attribute cache."
def at_script_creation(self):
"Setup the script"
self.key = "sys_cache_clear"
self.desc = _("Clears the Attribute Cache")
self.interval = 3600 * 2
self.persistent = True
def at_repeat(self):
"called every 2 hours. Sets a max attr-cache limit to 100 MB." # enough for normal usage?
if is_pypy:
# pypy don't support get_size, so we have to skip out here.
return
attr_cache_size, _, _ = caches.get_cache_sizes()
if attr_cache_size > _ATTRIBUTE_CACHE_MAXSIZE:
caches.flush_attr_cache()
#class ClearAttributeCache(Script):
# "Clear the attribute cache."
# def at_script_creation(self):
# "Setup the script"
# self.key = "sys_cache_clear"
# self.desc = _("Clears the Attribute Cache")
# self.interval = 3600 * 2
# self.persistent = True
# def at_repeat(self):
# "called every 2 hours. Sets a max attr-cache limit to 100 MB." # enough for normal usage?
# if is_pypy:
# # pypy don't support get_size, so we have to skip out here.
# return
# attr_cache_size, _, _ = caches.get_cache_sizes()
# if attr_cache_size > _ATTRIBUTE_CACHE_MAXSIZE:
# caches.flush_attr_cache()

View file

@ -97,27 +97,35 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg
update_fields = _GA(_GA(instance, "_meta"), "fields")
for field in update_fields:
fieldname = field.name
new_value = _GA(instance, fieldname)#field.value_from_object(instance)
# try to see if there is a handler on object that should be triggered when saving.
handlername = "_at_%s_save" % fieldname
handlername = "_at_%s_presave" % fieldname
handler = _GA(instance, handlername) if handlername in _GA(sender, '__dict__') else None
if callable(handler):
#hid = hashid(instance, "-%s" % fieldname)
try:
old_value = _GA(instance, _GA(field, "get_cache_name")())
except AttributeError:
old_value=None
# the handler may modify the stored value in various ways
# don't catch exceptions, the handler must work!
new_value = handler(new_value, old_value=old_value)
# we re-assign this to the field, save() will pick it up from there
_SA(instance, fieldname, new_value)
handler()
def field_post_save(sender, instance=None, update_fields=None, raw=False, **kwargs):
"""
Called at the beginning of the field save operation. The save method
must be called with the update_fields keyword in order to be most efficient.
This method should NOT save; rather it is the save() that triggers this function.
Its main purpose is to allow to plug-in a save handler and oob handlers.
"""
if raw:
return
if update_fields:
# this is a list of strings at this point. We want field objects
update_fields = (_GA(_GA(instance, "_meta"), "get_field_by_name")(field)[0] for field in update_fields)
else:
# meta.fields are already field objects; get them all
update_fields = _GA(_GA(instance, "_meta"), "fields")
for field in update_fields:
fieldname = field.name
handlername = "_at_%s_postsave" % fieldname
handler = _GA(instance, handlername) if handlername in _GA(sender, '__dict__') else None
if callable(handler):
handler()
trackerhandler = _GA(instance, "_trackerhandler") if "_trackerhandler" in _GA(instance, '__dict__') else None
if trackerhandler:
trackerhandler.update(fieldname, new_value)
#if hid:
# # update cache
# _FIELD_CACHE[hid] = new_value
trackerhandler.update(fieldname, _GA(instance, fieldname))
#------------------------------------------------------------
# Attr cache - caching the attribute objects related to a given object to
@ -125,63 +133,64 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg
# to any property).
#------------------------------------------------------------
# connected to m2m_changed signal in respective model class
def post_attr_update(sender, **kwargs):
"Called when the many2many relation changes (NOT when updating the value of an Attribute!)"
obj = kwargs['instance']
model = kwargs['model']
action = kwargs['action']
if kwargs['reverse']:
# the reverse relation changed (the Attribute itself was acted on)
pass
else:
# forward relation changed (the Object holding the Attribute m2m field)
if not kwargs["pk_set"]:
return
if action == "post_add":
# cache all added objects
for attr_id in kwargs["pk_set"]:
attr_obj = model.objects.get(pk=attr_id)
set_attr_cache(obj, _GA(attr_obj, "db_key"), attr_obj)
elif action == "post_remove":
# obj.db_attributes.remove(attr) was called
for attr_id in kwargs["pk_set"]:
attr_obj = model.objects.get(pk=attr_id)
del_attr_cache(obj, _GA(attr_obj, "db_key"))
attr_obj.delete()
elif action == "post_clear":
# obj.db_attributes.clear() was called
clear_obj_attr_cache(obj)
# access methods
def get_attr_cache(obj, attrname):
"Called by getting attribute"
hid = hashid(obj, "-%s" % attrname)
return _ATTR_CACHE.get(hid, None)
def set_attr_cache(obj, attrname, attrobj):
"Set the attr cache manually; this can be used to update"
global _ATTR_CACHE
hid = hashid(obj, "-%s" % attrname)
_ATTR_CACHE[hid] = attrobj
def del_attr_cache(obj, attrname):
"Del attribute cache"
global _ATTR_CACHE
hid = hashid(obj, "-%s" % attrname)
if hid in _ATTR_CACHE:
del _ATTR_CACHE[hid]
def flush_attr_cache():
"Clear attribute cache"
global _ATTR_CACHE
_ATTR_CACHE = {}
def clear_obj_attr_cache(obj):
global _ATTR_CACHE
hid = hashid(obj)
_ATTR_CACHE = {key:value for key, value in _ATTR_CACHE if not key.startswith(hid)}
## connected to m2m_changed signal in respective model class
#def post_attr_update(sender, **kwargs):
# "Called when the many2many relation changes (NOT when updating the value of an Attribute!)"
# obj = kwargs['instance']
# model = kwargs['model']
# action = kwargs['action']
# if kwargs['reverse']:
# # the reverse relation changed (the Attribute itself was acted on)
# pass
# else:
# # forward relation changed (the Object holding the Attribute m2m field)
# if not kwargs["pk_set"]:
# return
# if action == "post_add":
# # cache all added objects
# for attr_id in kwargs["pk_set"]:
# attr_obj = model.objects.get(pk=attr_id)
# set_attr_cache(obj, _GA(attr_obj, "db_key"), attr_obj)
# elif action == "post_remove":
# # obj.db_attributes.remove(attr) was called
# for attr_id in kwargs["pk_set"]:
# attr_obj = model.objects.get(pk=attr_id)
# del_attr_cache(obj, _GA(attr_obj, "db_key"))
# attr_obj.delete()
# elif action == "post_clear":
# # obj.db_attributes.clear() was called
# clear_obj_attr_cache(obj)
#
#
## attr cache - this is only left as deprecated cache
#
#def get_attr_cache(obj, attrname):
# "Called by getting attribute"
# hid = hashid(obj, "-%s" % attrname)
# return _ATTR_CACHE.get(hid, None)
#
#def set_attr_cache(obj, attrname, attrobj):
# "Set the attr cache manually; this can be used to update"
# global _ATTR_CACHE
# hid = hashid(obj, "-%s" % attrname)
# _ATTR_CACHE[hid] = attrobj
#
#def del_attr_cache(obj, attrname):
# "Del attribute cache"
# global _ATTR_CACHE
# hid = hashid(obj, "-%s" % attrname)
# if hid in _ATTR_CACHE:
# del _ATTR_CACHE[hid]
#
#def flush_attr_cache():
# "Clear attribute cache"
# global _ATTR_CACHE
# _ATTR_CACHE = {}
#
#def clear_obj_attr_cache(obj):
# global _ATTR_CACHE
# hid = hashid(obj)
# _ATTR_CACHE = {key:value for key, value in _ATTR_CACHE if not key.startswith(hid)}
#------------------------------------------------------------
# Property cache - this is a generic cache for properties stored on models.

View file

@ -152,8 +152,8 @@ def create_system_scripts():
# update the channel handler to make sure it's in sync
script3 = create.create_script(scripts.ValidateChannelHandler)
# clear the attribute cache regularly
script4 = create.create_script(scripts.ClearAttributeCache)
if not script1 or not script2 or not script3 or not script4:
#script4 = create.create_script(scripts.ClearAttributeCache)
if not script1 or not script2 or not script3:# or not script4:
print " Error creating system scripts."
def start_game_time():

View file

@ -32,15 +32,17 @@ from src.server.sessionhandler import SESSIONS
# setting up server-side field cache
from django.db.models.signals import pre_save
from django.db.models.signals import pre_save, post_save
from src.server.caches import field_pre_save
pre_save.connect(field_pre_save, dispatch_uid="fieldcache")
#pre_save.connect(field_pre_save, dispatch_uid="fieldcache")
post_save.connect(field_pre_save, dispatch_uid="fieldcache")
from django.db.models.signals import m2m_changed
from src.typeclasses.models import TypedObject
from src.server.caches import post_attr_update
#from src.server.caches import post_attr_update
#from django.db.models.signals import m2m_changed
# connect to attribute cache signal
m2m_changed.connect(post_attr_update, sender=TypedObject.db_attributes.through)
#m2m_changed.connect(post_attr_update, sender=TypedObject.db_attributes.through)
_SA = object.__setattr__

View file

@ -40,7 +40,7 @@ from django.utils.encoding import smart_str
from django.contrib.contenttypes.models import ContentType
from src.utils.idmapper.models import SharedMemoryModel
from src.server.caches import get_prop_cache, set_prop_cache, flush_attr_cache
from src.server.caches import get_prop_cache, set_prop_cache
#from src.server.caches import call_ndb_hooks
from src.server.models import ServerConfig
@ -634,99 +634,12 @@ class TypedObject(SharedMemoryModel):
# value = self.attr and del self.attr respectively (where self
# is the object in question).
# key property (wraps db_key)
#@property
#def __key_get(self):
# "Getter. Allows for value = self.key"
# #return _GA(self, "db_key")
# return get_field_cache(self, "key")
##@key.setter
#def __key_set(self, value):
# "Setter. Allows for self.key = value"
# set_field_cache(self, "key", value)
##@key.deleter
#def __key_del(self):
# "Deleter. Allows for del self.key"
# raise Exception("Cannot delete objectdb key!")
#key = property(__key_get, __key_set, __key_del)
# name property (alias to self.key)
def __name_get(self): return self.key
def __name_set(self, value): self.key = value
def __name_del(self): raise Exception("Cannot delete name")
name = property(__name_get, __name_set, __name_del)
# typeclass_path property - we manage this separately.
#@property
#def __typeclass_path_get(self):
# "Getter. Allows for value = self.typeclass_path"
# return _GA(self, "db_typeclass_path")
##@typeclass_path.setter
#def __typeclass_path_set(self, value):
# "Setter. Allows for self.typeclass_path = value"
# _SA(self, "db_typeclass_path", value)
# update_fields = ["db_typeclass_path"] if _GA(self, "_get_pk_val")(_GA(self, "_meta")) is not None else None
# _GA(self, "save")(update_fields=update_fields)
##@typeclass_path.deleter
#def __typeclass_path_del(self):
# "Deleter. Allows for del self.typeclass_path"
# self.db_typeclass_path = ""
# _GA(self, "save")(update_fields=["db_typeclass_path"])
#typeclass_path = property(__typeclass_path_get, __typeclass_path_set, __typeclass_path_del)
# date_created property
#@property
#def __date_created_get(self):
# "Getter. Allows for value = self.date_created"
# return get_field_cache(self, "date_created")
##@date_created.setter
#def __date_created_set(self, value):
# "Setter. Allows for self.date_created = value"
# raise Exception("Cannot change date_created!")
##@date_created.deleter
#def __date_created_del(self):
# "Deleter. Allows for del self.date_created"
# raise Exception("Cannot delete date_created!")
#date_created = property(__date_created_get, __date_created_set, __date_created_del)
# permissions property
#@property
#def __permissions_get(self):
# "Getter. Allows for value = self.name. Returns a list of permissions."
# perms = get_field_cache(self, "permissions")
# if perms:
# return [perm.strip() for perm in perms.split(',')]
# return []
##@permissions.setter
#def __permissions_set(self, value):
# "Setter. Allows for self.name = value. Stores as a comma-separated string."
# value = ",".join([utils.to_unicode(val).strip() for val in make_iter(value)])
# set_field_cache(self, "permissions", value)
##@permissions.deleter
#def __permissions_del(self):
# "Deleter. Allows for del self.name"
# self.db_permissions = ""
# self.save()
# del_field_cache(self, "permissions")
#permissions = property(__permissions_get, __permissions_set, __permissions_del)
# lock_storage property (wraps db_lock_storage)
#@property
#def __lock_storage_get(self):
# "Getter. Allows for value = self.lock_storage"
# return get_field_cache(self, "lock_storage")
##@lock_storage.setter
#def __lock_storage_set(self, value):
# """Saves the lock_storage. This is usually not called directly, but through self.lock()"""
# set_field_cache(self, "lock_storage", value)
##@lock_storage.deleter
#def __lock_storage_del(self):
# "Deleter is disabled. Use the lockhandler.delete (self.lock.delete) instead"""
# logger.log_errmsg("Lock_Storage (on %s) cannot be deleted. Use obj.lock.delete() instead." % self)
#lock_storage = property(__lock_storage_get, __lock_storage_set, __lock_storage_del)
#
#
# TypedObject main class methods and properties
@ -1000,14 +913,12 @@ class TypedObject(SharedMemoryModel):
"""
Type-level cleanup
"""
flush_attr_cache()
super(TypedObject, self).delete(*args, **kwargs)
#
# Object manipulation methods
#
#
def swap_typeclass(self, new_typeclass, clean_attributes=False, no_default=True):
"""
@ -1230,16 +1141,12 @@ class TypedObject(SharedMemoryModel):
raise Exception("Cannot delete the ndb object!")
ndb = property(__ndb_get, __ndb_set, __ndb_del)
#
# ***** DEPRECATED METHODS BELOW *******
#
#
# Fully attr_obj attributes. You usually access these
# Full attr_obj attributes. You usually access these
# through the obj.db.attrname method.
# Helper methods for attr_obj attributes