Cache changes: Moved all caches (except idmapper) to central caching module. This makes it easier to overview cache memory usage (and clean it) as well as plug-in external cache mechanisms.

This commit is contained in:
Griatch 2012-11-01 11:20:07 +01:00
parent 92f6b06626
commit d2d9953f94
8 changed files with 315 additions and 178 deletions

View file

@ -212,7 +212,7 @@ class CmdBan(MuxCommand):
# replace * with regex form and compile it
ipregex = ban.replace('.','\.')
ipregex = ipregex.replace('*', '[0-9]{1,3}')
print "regex:",ipregex
#print "regex:",ipregex
ipregex = re.compile(r"%s" % ipregex)
bantup = ("", ban, ipregex, now, reason)
# save updated banlist

View file

@ -281,7 +281,7 @@ class CmdGet(MuxCommand):
if caller == obj:
caller.msg("You can't get yourself.")
return
print obj, obj.location, caller, caller==obj.location
#print obj, obj.location, caller, caller==obj.location
if caller == obj.location:
caller.msg("You already hold that.")
return

View file

@ -11,6 +11,7 @@ import sys
import django, twisted
from django.conf import settings
from src.server.caches import get_cache_sizes
from src.server.sessionhandler import SESSIONS
from src.scripts.models import ScriptDB
from src.objects.models import ObjectDB
@ -607,13 +608,11 @@ class CmdServerLoad(MuxCommand):
if not utils.host_os_is('posix'):
string = "Process listings are only available under Linux/Unix."
else:
global _resource, _idmapper, _attribute_cache
global _resource, _idmapper
if not _resource:
import resource as _resource
if not _idmapper:
from src.utils.idmapper import base as _idmapper
if not _attribute_cache:
from src.typeclasses.models import _ATTRIBUTE_CACHE as _attribute_cache
import resource
loadavg = os.getloadavg()
@ -684,10 +683,13 @@ class CmdServerLoad(MuxCommand):
ftable = utils.format_table(table, 5)
for row in ftable:
string += "\n " + row[0] + row[1] + row[2]
# attribute cache
size = sum([sum([getsizeof(obj) for obj in dic.values()]) for dic in _attribute_cache.values()])/1024.0
count = sum([len(dic) for dic in _attribute_cache.values()])
string += "\n{w On-entity Attribute cache usage:{n %5.2f MB (%i items)" % (size, count)
# get sizes of other caches
attr_cache_info, field_cache_info, prop_cache_info = get_cache_sizes()
#size = sum([sum([getsizeof(obj) for obj in dic.values()]) for dic in _attribute_cache.values()])/1024.0
#count = sum([len(dic) for dic in _attribute_cache.values()])
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 Field cache usage:{n %5.2f MB (%i fields)" % (field_cache_info[1], field_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])
caller.msg(string)

View file

@ -20,7 +20,8 @@ from django.conf import settings
from src.utils.idmapper.models import SharedMemoryModel
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
from src.typeclasses.models import _get_cache, _set_cache, _del_cache
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache, hashid
from src.typeclasses.typeclass import TypeClass
from src.players.models import PlayerNick
from src.objects.manager import ObjectManager
@ -45,10 +46,6 @@ _ME = _("me")
_SELF = _("self")
_HERE = _("here")
def clean_content_cache(obj):
"Clean obj's content cache"
_SA(obj, "_contents_cache", None)
#------------------------------------------------------------
#
# ObjAttribute
@ -222,25 +219,24 @@ class ObjectDB(TypedObject):
#@property
def __aliases_get(self):
"Getter. Allows for value = self.aliases"
try:
return _GA(self, "_cached_aliases")
except AttributeError:
aliases = get_prop_cache(self, "_aliases")
if aliases == None:
aliases = list(Alias.objects.filter(db_obj=self).values_list("db_key", flat=True))
_SA(self, "_cached_aliases", aliases)
return aliases
set_prop_cache(self, "_aliases", aliases)
return aliases
#@aliases.setter
def __aliases_set(self, aliases):
"Setter. Allows for self.aliases = value"
for alias in make_iter(aliases):
new_alias = Alias(db_key=alias, db_obj=self)
new_alias.save()
_SA(self, "_cached_aliases", aliases)
set_prop_cache(self, "_aliases", aliases)
#@aliases.deleter
def __aliases_del(self):
"Deleter. Allows for del self.aliases"
for alias in Alias.objects.filter(db_obj=self):
alias.delete()
_DA(self, "_cached_aliases")
del_prop_cache(self, "_aliases")
aliases = property(__aliases_get, __aliases_set, __aliases_del)
# player property (wraps db_player)
@ -251,24 +247,24 @@ class ObjectDB(TypedObject):
We have to be careful here since Player is also
a TypedObject, so as to not create a loop.
"""
return _get_cache(self, "player")
return get_field_cache(self, "player")
#@player.setter
def __player_set(self, player):
"Setter. Allows for self.player = value"
if inherits_from(player, TypeClass):
player = player.dbobj
_set_cache(self, "player", player)
set_field_cache(self, "player", player)
#@player.deleter
def __player_del(self):
"Deleter. Allows for del self.player"
_del_cache(self, "player")
del_field_cache(self, "player")
player = property(__player_get, __player_set, __player_del)
# location property (wraps db_location)
#@property
def __location_get(self):
"Getter. Allows for value = self.location."
loc = _get_cache(self, "location")
loc = get_field_cache(self, "location")
if loc:
return _GA(loc, "typeclass")
return None
@ -298,20 +294,20 @@ class ObjectDB(TypedObject):
except RuntimeWarning: pass
# set the location
_set_cache(self, "location", loc)
set_field_cache(self, "location", loc)
# update the contents of each location
if old_loc:
_GA(_GA(old_loc, "dbobj"), "contents_update")(self, remove=True)
_GA(_GA(old_loc, "dbobj"), "contents_update")()
if loc:
_GA(loc, "contents_update")(_GA(self, "typeclass"))
_GA(loc, "contents_update")()
except RuntimeError:
string = "Cannot set location: "
string += "%s.location = %s would create a location-loop." % (self.key, location)
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:
string = "Cannot set location: "
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)
@ -319,17 +315,17 @@ class ObjectDB(TypedObject):
#@location.deleter
def __location_del(self):
"Deleter. Allows for del self.location"
_GA(self, "location").contents_update(self, remove=True)
_GA(self, "location").contents_update()
_SA(self, "db_location", None)
_GA(self, "save")()
_del_cache(self, "location")
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_cache(self, "home")
home = get_field_cache(self, "home")
if home:
return _GA(home, "typeclass")
return None
@ -347,7 +343,7 @@ class ObjectDB(TypedObject):
hom = _GA(home, "dbobj")
else:
hom = _GA(home, "dbobj")
_set_cache(self, "home", hom)
set_field_cache(self, "home", hom)
except Exception:
string = "Cannot set home: "
string += "%s is not a valid home."
@ -359,14 +355,14 @@ class ObjectDB(TypedObject):
"Deleter. Allows for del self.home."
_SA(self, "db_home", None)
_GA(self, "save")()
_del_cache(self, "home")
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_cache(self, "destination")
dest = get_field_cache(self, "destination")
if dest:
return _GA(dest, "typeclass")
return None
@ -386,7 +382,7 @@ class ObjectDB(TypedObject):
dest = _GA(destination, "dbobj")
else:
dest = destination.dbobj
_set_cache(self, "destination", dest)
set_field_cache(self, "destination", dest)
except Exception:
string = "Cannot set destination: "
string += "%s is not a valid destination." % destination
@ -398,7 +394,7 @@ class ObjectDB(TypedObject):
"Deleter. Allows for del self.destination"
_SA(self, "db_destination", None)
_GA(self, "save")()
_del_cache(self, "destination")
del_field_cache(self, "destination")
destination = property(__destination_get, __destination_set, __destination_del)
# cmdset_storage property.
@ -461,13 +457,11 @@ class ObjectDB(TypedObject):
#@property
def __is_superuser_get(self):
"Check if user has a player, and if so, if it is a superuser."
#return any(self.sessions) and self.player.is_superuser
return any(_GA(self, "sessions")) and _GA(_GA(self, "player"), "is_superuser")
is_superuser = property(__is_superuser_get)
# contents
_contents_cache = None
#@property
def contents_get(self, exclude=None):
"""
@ -477,29 +471,25 @@ class ObjectDB(TypedObject):
exclude is one or more objects to not return
"""
if _GA(self, "_contents_cache") == None:
# create the cache
_SA(self, "_contents_cache", dict((obj.id, obj) for obj in ObjectDB.objects.get_contents(self)))
if exclude:
exclude = make_iter(exclude)
return [obj for obj in _GA(self, "_contents_cache").values() if obj not in exclude]
return _GA(self, "_contents_cache").values()
#return ObjectDB.objects.get_contents(self, excludeobj=exclude)
cont = get_prop_cache(self, "_contents")
exclude = make_iter(exclude)
if cont == None:
cont = _GA(self, "contents_update")()
return [obj for obj in cont if obj not in exclude]
contents = property(contents_get)
def contents_update(self, obj, remove=False):
def contents_update(self):
"""
Updates the contents property of the object. Called by
Updates the contents property of the object with a new
object Called by
self.location_set.
obj -
remove (true/false) - remove obj from content list
"""
# this creates/updates the cache
_GA(self, "contents")
# set/remove objects from contents cache
cache = _GA(self, "_contents_cache")
if remove and obj.id in cache:
del cache[obj.id]
else:
cache[obj.id] = obj
cont = ObjectDB.objects.get_contents(self)
set_prop_cache(self, "_contents", cont)
return cont
#@property
def __exits_get(self):
@ -941,9 +931,10 @@ class ObjectDB(TypedObject):
_GA(self, "clear_exits")()
# Clear out any non-exit objects located within the object
_GA(self, "clear_contents")()
# clear current location's content cache of this object
if _GA(self, "location"):
_GA(self, "location").contents_update(self, remove=True)
old_loc = _GA(self, "location")
# Perform the deletion of the object
super(ObjectDB, self).delete()
# clear object's old location's content cache of this object
if old_loc:
old_loc.contents_update()
return True

View file

@ -45,7 +45,8 @@ from django.db import models
from django.contrib.auth.models import User
from django.utils.encoding import smart_str
from src.typeclasses.models import _get_cache, _set_cache, _del_cache
from src.server.caches import get_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
from src.server.sessionhandler import SESSIONS
from src.players import manager
from src.typeclasses.models import Attribute, TypedObject, TypeNick, TypeNickHandler
@ -196,7 +197,7 @@ class PlayerDB(TypedObject):
#@property
def obj_get(self):
"Getter. Allows for value = self.obj"
return _get_cache(self, "obj")
return get_field_cache(self, "obj")
#@obj.setter
def obj_set(self, value):
"Setter. Allows for self.obj = value"
@ -207,14 +208,14 @@ class PlayerDB(TypedObject):
if isinstance(value, _TYPECLASS):
value = value.dbobj
try:
_set_cache(self, "obj", value)
set_field_cache(self, "obj", value)
except Exception:
logger.log_trace()
raise Exception("Cannot assign %s as a player object!" % value)
#@obj.deleter
def obj_del(self):
"Deleter. Allows for del self.obj"
_del_cache(self, "obj")
del_field_cache(self, "obj")
obj = property(obj_get, obj_set, obj_del)
# whereas the name 'obj' is consistent with the rest of the code,
@ -223,17 +224,17 @@ class PlayerDB(TypedObject):
#@property
def character_get(self):
"Getter. Allows for value = self.character"
return _get_cache(self, "obj")
return get_field_cache(self, "obj")
#@character.setter
def character_set(self, character):
"Setter. Allows for self.character = value"
if inherits_from(character, TypeClass):
character = character.dbobj
_set_cache(self, "obj", character)
set_field_cache(self, "obj", character)
#@character.deleter
def character_del(self):
"Deleter. Allows for del self.character"
_del_cache(self, "obj")
del_field_cache(self, "obj")
character = property(character_get, character_set, character_del)
# cmdset_storage property
# This seems very sensitive to caching, so leaving it be for now /Griatch
@ -260,15 +261,15 @@ class PlayerDB(TypedObject):
#@property
def is_connected_get(self):
"Getter. Allows for value = self.is_connected"
return _get_cache(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_cache(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_cache(self, "is_connected", False)
set_field_cache(self, "is_connected", False)
is_connected = property(is_connected_get, is_connected_set, is_connected_del)
class Meta:
@ -292,20 +293,21 @@ class PlayerDB(TypedObject):
_db_model_name = "playerdb" # used by attributes to safely store objects
_default_typeclass_path = settings.BASE_PLAYER_TYPECLASS or "src.players.player.Player"
_name_cache = None
# name property (wraps self.user.username)
#@property
def name_get(self):
"Getter. Allows for value = self.name"
if not _GA(self, "_name_cache"):
_SA(self, "_name_cache", _GA(self,"user").username)
return _GA(self, "_name_cache")
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"
_GA(self, "user").username = value
_GA(self, "user").save()
_SA(self, "_name_cache", value)
set_prop_cache(self, "_name", value)
#@name.deleter
def name_del(self):
"Deleter. Allows for del self.name"
@ -313,13 +315,14 @@ class PlayerDB(TypedObject):
name = property(name_get, name_set, name_del)
key = property(name_get, name_set, name_del)
_uid_cache = None
#@property
def uid_get(self):
"Getter. Retrieves the user id"
if not _GA(self, "_uid_cache"):
_SA(self, "_uid_cache", _GA(self, "user").id)
return _GA(self, "_uid_cache")
uid = get_prop_cache(self, "_uid")
if not uid:
uid = _GA(self, "user").id
set_prop_cache(self, "_uid", uid)
return uid
def uid_set(self, value):
raise Exception("User id cannot be set!")
def uid_del(self):
@ -342,12 +345,13 @@ class PlayerDB(TypedObject):
sessions = property(sessions_get, sessions_set, sessions_del)
#@property
_is_superuser_cache = None
def is_superuser_get(self):
"Superusers have all permissions."
if _GA(self, "_is_superuser_cache") == None:
_SA(self, "_is_superuser_cache", _GA(self, "user").is_superuser)
return _GA(self, "_is_superuser_cache")
is_suser = get_prop_cache(self, "_is_superuser")
if is_suser == None:
is_suser = _GA(self, "user").is_superuser
set_prop_cache(self, "_is_superuser", is_suser)
return is_suser
is_superuser = property(is_superuser_get)
#

166
src/server/caches.py Normal file
View file

@ -0,0 +1,166 @@
"""
Central caching module.
"""
from sys import getsizeof
from collections import defaultdict
from weakref import WeakKeyDictionary
_GA = object.__getattribute__
_SA = object.__setattr__
_DA = object.__delattr__
# Cache stores
_ATTR_CACHE = defaultdict(dict)
_FIELD_CACHE = defaultdict(dict)
_PROP_CACHE = defaultdict(dict)
def get_cache_sizes():
"""
Get cache sizes, expressed in number of objects and memory size in MB
"""
global _ATTR_CACHE, _FIELD_CACHE, _PROP_CACHE
attr_n = sum(len(dic) for dic in _ATTR_CACHE.values())
attr_mb = sum(sum(getsizeof(obj) for obj in dic.values()) for dic in _ATTR_CACHE.values()) / 1024.0
field_n = sum(len(dic) for dic in _FIELD_CACHE.values())
field_mb = sum(sum([getsizeof(obj) for obj in dic.values()]) for dic in _FIELD_CACHE.values()) / 1024.0
prop_n = sum(len(dic) for dic in _PROP_CACHE.values())
prop_mb = sum(sum([getsizeof(obj) for obj in dic.values()]) for dic in _PROP_CACHE.values()) / 1024.0
return (attr_n, attr_mb), (field_n, field_mb), (prop_n, prop_mb)
def hashid(obj):
"""
Returns a per-class unique that combines the object's
class name with its idnum and creation time. This makes this id unique also
between different typeclassed entities such as scripts and
objects (which may still have the same id).
"""
try:
hid = _GA(obj, "_hashid")
except AttributeError:
date, idnum = _GA(obj, "db_date_created"), _GA(obj, "id")
if not idnum or not date:
# this will happen if setting properties on an object
# which is not yet saved
return None
# build the hashid
hid = "%s-%s-#%s" % (_GA(obj, "__class__"), date, idnum)
_SA(obj, "_hashid", hid)
return hid
# on-object database field cache
def get_field_cache(obj, name):
"On-model Cache handler."
global _FIELD_CACHE
hid = hashid(obj)
if hid:
try:
return _FIELD_CACHE[hid][name]
except KeyError:
val = _GA(obj, "db_%s" % name)
_FIELD_CACHE[hid][name] = val
return val
return _GA(obj, "db_%s" % name)
def set_field_cache(obj, name, val):
"On-model Cache setter. Also updates database."
_SA(obj, "db_%s" % name, val)
_GA(obj, "save")()
hid = hashid(obj)
if hid:
global _FIELD_CACHE
_FIELD_CACHE[hid][name] = val
def del_field_cache(obj, name):
"On-model cache deleter"
hid = hashid(obj)
if hid:
try:
del _FIELD_CACHE[hid][name]
except KeyError:
pass
def flush_field_cache(obj):
"On-model cache resetter"
hid = hashid(obj)
if hid:
global _FIELD_CACHE
del _FIELD_CACHE[hashid(obj)]
# on-object property cache (unrelated to database)
# Note that the get/set_prop_cache handler do not actually
# get/set the property "on" the object but only reads the
# value to/from the cache. This is intended to be used
# with a get/setter property on the object.
def get_prop_cache(obj, name, default=None):
"On-model Cache handler."
global _PROP_CACHE
hid = hashid(obj)
if hid:
try:
return _PROP_CACHE[hid][name]
except KeyError:
return default
_PROP_CACHE[hid][name] = val
return val
return default
def set_prop_cache(obj, name, val):
"On-model Cache setter. Also updates database."
hid = hashid(obj)
if hid:
global _PROP_CACHE
_PROP_CACHE[hid][name] = val
def del_prop_cache(obj, name):
"On-model cache deleter"
try:
del _PROP_CACHE[hashid(obj)][name]
except KeyError:
pass
def flush_field_cache(obj):
"On-model cache resetter"
hid = hashid(obj)
if hid:
global _PROP_CACHE
del _PROP_CACHE[hashid(obj)]
# attribute cache
def get_attr_cache(obj, attrname):
"""
Attribute cache store
"""
return _ATTR_CACHE[hashid(obj)].get(attrname)
def set_attr_cache(obj, attrname, attrobj):
"""
Cache an attribute object
"""
global _ATTR_CACHE
_ATTR_CACHE[hashid(obj)][attrname] = attrobj
def del_attr_cache(obj, attrname):
"""
Remove attribute from cache
"""
global _ATTR_CACHE
try:
del _ATTR_CACHE[hashid(obj)][attrname]
except KeyError:
pass
def flush_attr_cache(obj):
"""
Flush the attribute cache for this object.
"""
global _ATTR_CACHE
del _ATTR_CACHE[hashid(obj)]

View file

@ -45,7 +45,6 @@ def create_objects():
# accessed by user.get_profile() and can also store attributes.
# It also holds mud permissions, but for a superuser these
# have no effect anyhow.
character_typeclass = settings.BASE_CHARACTER_TYPECLASS
# Create the Player object as well as the in-game god-character
@ -85,7 +84,6 @@ def create_objects():
if not god_character.home:
god_character.home = limbo_obj
def create_channels():
"""
Creates some sensible default channels.

View file

@ -39,6 +39,9 @@ from django.conf import settings
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_field_cache, set_field_cache, del_field_cache
from src.server.caches import get_attr_cache, set_attr_cache, del_attr_cache
from src.server.caches import get_prop_cache, set_prop_cache, del_prop_cache
from src.server.models import ServerConfig
from src.typeclasses import managers
from src.locks.lockhandler import LockHandler
@ -59,28 +62,28 @@ _PDUMPS = pickle.dumps
# Property Cache mechanism.
def _get_cache(obj, name):
"On-model Cache handler."
try:
return _GA(obj, "_cached_db_%s" % name)
except AttributeError:
val = _GA(obj, "db_%s" % name)
_SA(obj, "_cached_db_%s" % name, val)
return val
def _set_cache(obj, name, val):
"On-model Cache setter. Also updates database."
_SA(obj, "db_%s" % name, val)
_GA(obj, "save")()
_SA(obj, "_cached_db_%s" % name, val)
def _del_cache(obj, name):
"On-model cache deleter"
try:
_DA(obj, "_cached_db_%s" % name)
except AttributeError:
pass
def _clean_cache(obj):
"On-model cache resetter"
[_DA(obj, cname) for cname in obj.__dict__.keys() if cname.startswith("_cached_db_")]
#def _get_cache(obj, name):
# "On-model Cache handler."
# try:
# return _GA(obj, "_cached_db_%s" % name)
# except AttributeError:
# val = _GA(obj, "db_%s" % name)
# _SA(obj, "_cached_db_%s" % name, val)
# return val
#def set_prop_cache(obj, name, val):
# "On-model Cache setter. Also updates database."
# _SA(obj, "db_%s" % name, val)
# _GA(obj, "save")()
# _SA(obj, "_cached_db_%s" % name, val)
#def del_prop_cache(obj, name):
# "On-model cache deleter"
# try:
# _DA(obj, "_cached_db_%s" % name)
# except AttributeError:
# pass
#def _clean_cache(obj):
# "On-model cache resetter"
# [_DA(obj, cname) for cname in obj.__dict__.keys() if cname.startswith("_cached_db_")]
# this cache holds the attributes loaded on objects, one dictionary
@ -371,11 +374,11 @@ class Attribute(SharedMemoryModel):
#@property
def __key_get(self):
"Getter. Allows for value = self.key"
return _get_cache(self, "key")
return get_field_cache(self, "key")
#@key.setter
def __key_set(self, value):
"Setter. Allows for self.key = value"
_set_cache(self, "key", value)
set_field_cache(self, "key", value)
#@key.deleter
def __key_del(self):
"Deleter. Allows for del self.key"
@ -386,24 +389,24 @@ class Attribute(SharedMemoryModel):
#@property
def __obj_get(self):
"Getter. Allows for value = self.obj"
return _get_cache(self, "obj")
return get_field_cache(self, "obj")
#@obj.setter
def __obj_set(self, value):
"Setter. Allows for self.obj = value"
_set_cache(self, "obj", value)
set_field_cache(self, "obj", value)
#@obj.deleter
def __obj_del(self):
"Deleter. Allows for del self.obj"
self.db_obj = None
self.save()
_del_cache(self, "obj")
del_field_cache(self, "obj")
obj = property(__obj_get, __obj_set, __obj_del)
# date_created property (wraps db_date_created)
#@property
def __date_created_get(self):
"Getter. Allows for value = self.date_created"
return _get_cache(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"
@ -454,7 +457,7 @@ class Attribute(SharedMemoryModel):
#@property
def __lock_storage_get(self):
"Getter. Allows for value = self.lock_storage"
return _get_cache(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()"""
@ -830,11 +833,11 @@ class TypedObject(SharedMemoryModel):
#@property
def __key_get(self):
"Getter. Allows for value = self.key"
return _get_cache(self, "key")
return get_field_cache(self, "key")
#@key.setter
def __key_set(self, value):
"Setter. Allows for self.key = value"
_set_cache(self, "key", value)
set_field_cache(self, "key", value)
#@key.deleter
def __key_del(self):
"Deleter. Allows for del self.key"
@ -845,11 +848,11 @@ class TypedObject(SharedMemoryModel):
#@property
def __name_get(self):
"Getter. Allows for value = self.name"
return _get_cache(self, "key")
return get_field_cache(self, "key")
#@name.setter
def __name_set(self, value):
"Setter. Allows for self.name = value"
_set_cache(self, "key", value)
set_field_cache(self, "key", value)
#@name.deleter
def __name_del(self):
"Deleter. Allows for del self.name"
@ -860,24 +863,24 @@ class TypedObject(SharedMemoryModel):
#@property
def __typeclass_path_get(self):
"Getter. Allows for value = self.typeclass_path"
return _get_cache(self, "typeclass_path")
return get_field_cache(self, "typeclass_path")
#@typeclass_path.setter
def __typeclass_path_set(self, value):
"Setter. Allows for self.typeclass_path = value"
_set_cache(self, "typeclass_path", value)
set_field_cache(self, "typeclass_path", value)
#@typeclass_path.deleter
def __typeclass_path_del(self):
"Deleter. Allows for del self.typeclass_path"
self.db_typeclass_path = ""
self.save()
_del_cache(self, "typeclass_path")
del_field_cache(self, "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_cache(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"
@ -892,7 +895,7 @@ class TypedObject(SharedMemoryModel):
#@property
def __permissions_get(self):
"Getter. Allows for value = self.name. Returns a list of permissions."
perms = _get_cache(self, "permissions")
perms = get_field_cache(self, "permissions")
if perms:
return [perm.strip() for perm in perms.split(',')]
return []
@ -900,24 +903,24 @@ class TypedObject(SharedMemoryModel):
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_cache(self, "permissions", 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_cache(self, "permissions")
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_cache(self, "lock_storage")
return get_field_cache(self, "lock_storage")
#@lock_storage.setter
def __lock_storage_set(self, value):
"""Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
_set_cache(self, "lock_storage", value)
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"""
@ -975,16 +978,15 @@ class TypedObject(SharedMemoryModel):
return False
#@property
_dbid_cache = None
def __dbid_get(self):
"""
Caches and returns the unique id of the object.
Use this instead of self.id, which is not cached.
"""
dbid = _GA(self, "_dbid_cache")
dbid = get_prop_cache(self, "_dbid")
if not dbid:
dbid = _GA(self, "id")
_SA(self, "_dbid_cache", dbid)
set_prop_cache(self, "_dbid", dbid)
return dbid
def __dbid_set(self, value):
raise Exception("dbid cannot be set!")
@ -1004,26 +1006,6 @@ class TypedObject(SharedMemoryModel):
raise Exception("dbref cannot be deleted!")
dbref = property(__dbref_get, __dbref_set, __dbref_del)
#@property
_hashid_cache = None
def __hashid_get(self):
"""
Returns a per-class unique that combines the object's
class name with its idnum. This makes this id unique also
between different typeclassed entities such as scripts and
objects (which may still have the same id).
Primarily used by Attribute caching system.
"""
hashid = _GA(self, "_hashid_cache")
if not hashid:
hashid = "%s<#%s>" % (_GA(self, "__class__"), _GA(self, "dbid"))
_SA(self, "_hashid_cache", hashid)
return hashid
def __hashid_set(self):
raise Exception("hashid cannot be set!")
def __hashid_del(self):
raise Exception("hashid cannot be deleted!")
hashid = property(__hashid_get, __hashid_set, __hashid_del)
# typeclass property
#@property
@ -1333,11 +1315,11 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name.
"""
if attribute_name not in _ATTRIBUTE_CACHE[_GA(self, "hashid")]:
if attribute_name not in get_attr_cache(self):
attrib_obj = _GA(self, "_attribute_class").objects.filter(db_obj=self).filter(
db_key__iexact=attribute_name)
if attrib_obj:
_ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name] = attrib_obj[0]
set_attr_cache(self, attribute_name, attrib_obj[0])
else:
return False
return True
@ -1351,7 +1333,7 @@ class TypedObject(SharedMemoryModel):
new_value: (python obj) The value to set the attribute to. If this is not
a str, the object will be stored as a pickle.
"""
attrib_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get("attribute_name")
attrib_obj = get_attr_cache(self, attribute_name)
if not attrib_obj:
attrclass = _GA(self, "_attribute_class")
# check if attribute already exists.
@ -1369,24 +1351,23 @@ class TypedObject(SharedMemoryModel):
except IntegrityError:
# this can happen if the cache was stale and the databse object is
# missing. If so we need to clean self.hashid from the cache
if _GA(self, "hashid") in _ATTRIBUTE_CACHE:
del _ATTRIBUTE_CACHE[_GA(self, "hashid")]
self.delete()
flush_attr_cache(self)
self.delete()
raise IntegrityError("Attribute could not be saved - object %s was deleted from database." % self.key)
_ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name] = attrib_obj
set_attr_cache(self, attribute_name, attrib_obj)
def get_attribute_obj(self, attribute_name, default=None):
"""
Get the actual attribute object named attribute_name
"""
attrib_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get(attribute_name)
attrib_obj = get_attribute_cache(self, attribute_name)
if not attrib_obj:
attrib_obj = _GA(self, "_attribute_class").objects.filter(
db_obj=self).filter(db_key__iexact=attribute_name)
if not attrib_obj:
return default
_ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name] = attrib_obj[0] #query is first evaluated here
return _ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name]
set_attr_cache(self, attribute_name, attrib_obj[0]) #query is first evaluated here
return attrib_obj[0]
return attrib_obj
def get_attribute(self, attribute_name, default=None):
@ -1398,14 +1379,14 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name.
default: What to return if no attribute is found
"""
attrib_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get(attribute_name)
attrib_obj = get_attr_cache(self, attribute_name)
if not attrib_obj:
attrib_obj = _GA(self, "_attribute_class").objects.filter(
db_obj=self).filter(db_key__iexact=attribute_name)
if not attrib_obj:
return default
_ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name] = attrib_obj[0] #query is first evaluated here
return _ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name].value
set_attr_cache(self, attribute_name, attrib_obj[0]) #query is first evaluated here
return attrib_obj[0].value
return attrib_obj.value
def get_attribute_raise(self, attribute_name):
@ -1415,14 +1396,14 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name.
"""
attrib_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get(attribute_name)
attrib_obj = get_attr_cache(self, attribute_name)
if not attrib_obj:
attrib_obj = _GA(self, "_attribute_class").objects.filter(
db_obj=self).filter(db_key__iexact=attribute_name)
if not attrib_obj:
raise AttributeError
_ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name] = attrib_obj[0] #query is first evaluated here
return _ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name].value
set_attr_cache(self, attribute_name, attrib_obj[0]) #query is first evaluated here
return attrib_obj[0].value
return attrib_obj.value
def del_attribute(self, attribute_name):
@ -1431,9 +1412,9 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name.
"""
attr_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get(attribute_name)
attr_obj = get_attr_cache(self, attribute_name)
if attr_obj:
del _ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name]
del_attr_cache(self, attribute_name)
attr_obj.delete()
else:
try:
@ -1449,9 +1430,9 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name.
"""
attr_obj = _ATTRIBUTE_CACHE[_GA(self, "hashid")].get(attribute_name)
attr_obj = get_attr_cache(self, attribute_name)
if attr_obj:
del _ATTRIBUTE_CACHE[_GA(self, "hashid")][attribute_name]
del_attr_cache(self, attribute_name)
attr_obj.delete()
else:
try:
@ -1695,11 +1676,6 @@ class TypedObject(SharedMemoryModel):
if hperm in [p.lower() for p in self.permissions] and hpos > ppos)
return False
def flush_attr_cache(self):
"""
Flush only the attribute cache for this object.
"""
_ATTRIBUTE_CACHE[_GA(self, "hashid")] = {}
def flush_from_cache(self):
"""