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:
parent
92f6b06626
commit
d2d9953f94
8 changed files with 315 additions and 178 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
166
src/server/caches.py
Normal 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)]
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue