Added fix to object.contents cache as well as reworked the extent of cache hooks on location modification.
This commit is contained in:
parent
07af616b67
commit
06a0bea8d6
11 changed files with 125 additions and 653 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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('#'))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue