Added aggressive caching for common typeclassed variables.

This commit is contained in:
Griatch 2012-02-25 23:37:50 +01:00
parent b99db98191
commit 1fa5791e19
3 changed files with 56 additions and 69 deletions

View file

@ -22,7 +22,8 @@ except ImportError:
from twisted.protocols import amp from twisted.protocols import amp
from twisted.internet import protocol, defer from twisted.internet import protocol, defer
from django.conf import settings from django.conf import settings
from src.utils import utils from src.utils.utils import to_str
from src.server.models import ServerConfig from src.server.models import ServerConfig
from src.scripts.models import ScriptDB from src.scripts.models import ScriptDB
from src.players.models import PlayerDB from src.players.models import PlayerDB
@ -77,8 +78,6 @@ class AmpServerFactory(protocol.ServerFactory):
self.server.amp_protocol.factory = self self.server.amp_protocol.factory = self
return self.server.amp_protocol return self.server.amp_protocol
class AmpClientFactory(protocol.ReconnectingClientFactory): class AmpClientFactory(protocol.ReconnectingClientFactory):
""" """
This factory creates new AMPProtocol protocol instances to use to connect This factory creates new AMPProtocol protocol instances to use to connect
@ -193,8 +192,8 @@ class PortalAdmin(amp.Command):
errors = [(Exception, 'EXCEPTION')] errors = [(Exception, 'EXCEPTION')]
response = [] response = []
dumps = lambda data: utils.to_str(pickle.dumps(data, pickle.HIGHEST_PROTOCOL)) dumps = lambda data: to_str(pickle.dumps(data, pickle.HIGHEST_PROTOCOL))
loads = lambda data: pickle.loads(utils.to_str(data)) loads = lambda data: pickle.loads(to_str(data))
#------------------------------------------------------------ #------------------------------------------------------------
# Core AMP protocol for communication Server <-> Portal # Core AMP protocol for communication Server <-> Portal
@ -279,7 +278,7 @@ class AMPProtocol(amp.AMP):
#print "msg server->portal (server side):", sessid, msg, data #print "msg server->portal (server side):", sessid, msg, data
self.callRemote(MsgServer2Portal, self.callRemote(MsgServer2Portal,
sessid=sessid, sessid=sessid,
msg=utils.to_str(msg), msg=to_str(msg),
data=dumps(data)).addErrback(self.errback, "OOBServer2Portal") data=dumps(data)).addErrback(self.errback, "OOBServer2Portal")
# OOB Portal -> Server # OOB Portal -> Server
@ -367,7 +366,7 @@ class AMPProtocol(amp.AMP):
sesslist.append(sess) sesslist.append(sess)
# replace sessions on server # replace sessions on server
server_sessionhandler.portal_session_sync(sesslist) server_sessionhandler.portal_session_sync(sesslist)
# after sync is complete we force-validate all scripts (this starts everthing) # after sync is complete we force-validate all scripts (this starts everything)
init_mode = ServerConfig.objects.conf("server_restart_mode", default=None) init_mode = ServerConfig.objects.conf("server_restart_mode", default=None)
ScriptDB.objects.validate(init_mode=init_mode) ScriptDB.objects.validate(init_mode=init_mode)
ServerConfig.objects.conf("server_restart_mode", delete=True) ServerConfig.objects.conf("server_restart_mode", delete=True)

View file

@ -52,17 +52,14 @@ DA = object.__delattr__
PLOADS = pickle.loads PLOADS = pickle.loads
PDUMPS = pickle.dumps PDUMPS = pickle.dumps
def get_cache(obj, name):
# # used by Attribute to efficiently identify stored object types. "On-model Cache handler."
# # Note that these have to be updated if directory structure changes. try:
# PARENTS = { return GA(obj, "_cached_db_%s" % name)
# "typeclass":"src.typeclasses.typeclass.TypeClass", except AttributeError:
# "objectdb":"src.objects.models.ObjectDB", val = GA(obj, "db_%s" % name)
# "playerdb":"src.players.models.PlayerDB", SA(obj, "_cached_db_%s" % name, val)
# "scriptdb":"src.scripts.models.ScriptDB", return val
# "msg":"src.comms.models.Msg",
# "channel":"src.comms.models.Channel",
# "helpentry":"src.help.models.HelpEntry"}
#------------------------------------------------------------ #------------------------------------------------------------
# #
@ -280,8 +277,8 @@ class Attribute(SharedMemoryModel):
# key property (wraps db_key) # key property (wraps db_key)
#@property #@property
def key_get(self): def key_get(self):
"Getter. Allows for value = self.key" "Getter. Allows for value = self.key"
return self.db_key return get_cache(self, "key")
#@key.setter #@key.setter
def key_set(self, value): def key_set(self, value):
"Setter. Allows for self.key = value" "Setter. Allows for self.key = value"
@ -297,7 +294,7 @@ class Attribute(SharedMemoryModel):
#@property #@property
def obj_get(self): def obj_get(self):
"Getter. Allows for value = self.obj" "Getter. Allows for value = self.obj"
return self.db_obj return get_cache(self, "db_obj")
#@obj.setter #@obj.setter
def obj_set(self, value): def obj_set(self, value):
"Setter. Allows for self.obj = value" "Setter. Allows for self.obj = value"
@ -314,7 +311,7 @@ class Attribute(SharedMemoryModel):
#@property #@property
def date_created_get(self): def date_created_get(self):
"Getter. Allows for value = self.date_created" "Getter. Allows for value = self.date_created"
return self.db_date_created return get_cache(self, "db_date_created")
#@date_created.setter #@date_created.setter
def date_created_set(self, value): def date_created_set(self, value):
"Setter. Allows for self.date_created = value" "Setter. Allows for self.date_created = value"
@ -364,7 +361,7 @@ class Attribute(SharedMemoryModel):
#@property #@property
def lock_storage_get(self): def lock_storage_get(self):
"Getter. Allows for value = self.lock_storage" "Getter. Allows for value = self.lock_storage"
return self.db_lock_storage return get_cache(self, "lock_storage")
#@lock_storage.setter #@lock_storage.setter
def lock_storage_set(self, value): def lock_storage_set(self, value):
"""Saves the lock_storage. This is usually not called directly, but through self.lock()""" """Saves the lock_storage. This is usually not called directly, but through self.lock()"""
@ -669,8 +666,7 @@ class TypedObject(SharedMemoryModel):
objects = managers.TypedObjectManager() objects = managers.TypedObjectManager()
# object cache and flags # object cache and flags
cached_typeclass_path = "" _cached_typeclass = None
cached_typeclass = None
# lock handler self.locks # lock handler self.locks
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -698,12 +694,12 @@ class TypedObject(SharedMemoryModel):
#@property #@property
def key_get(self): def key_get(self):
"Getter. Allows for value = self.key" "Getter. Allows for value = self.key"
return self.db_key return get_cache(self, "key")
#@key.setter #@key.setter
def key_set(self, value): def key_set(self, value):
"Setter. Allows for self.key = value" "Setter. Allows for self.key = value"
self.db_key = value SA(self, "db_key", value)
self.save() GA(self, "save")()
#@key.deleter #@key.deleter
def key_del(self): def key_del(self):
"Deleter. Allows for del self.key" "Deleter. Allows for del self.key"
@ -714,12 +710,12 @@ class TypedObject(SharedMemoryModel):
#@property #@property
def name_get(self): def name_get(self):
"Getter. Allows for value = self.name" "Getter. Allows for value = self.name"
return self.db_key return get_cache(self, "key")
#@name.setter #@name.setter
def name_set(self, value): def name_set(self, value):
"Setter. Allows for self.name = value" "Setter. Allows for self.name = value"
self.db_key = value SA(self, "db_key", value)
self.save() GA(self, "save")()
#@name.deleter #@name.deleter
def name_del(self): def name_del(self):
"Deleter. Allows for del self.name" "Deleter. Allows for del self.name"
@ -729,30 +725,27 @@ class TypedObject(SharedMemoryModel):
# typeclass_path property # typeclass_path property
#@property #@property
def typeclass_path_get(self): def typeclass_path_get(self):
"Getter. Allows for value = self.typeclass_path" "Getter. Allows for value = self.typeclass_path"
typeclass_path = GA(self, 'cached_typeclass_path') return get_cache(self, "typeclass_path")
if typeclass_path:
return typeclass_path
return self.db_typeclass_path
#@typeclass_path.setter #@typeclass_path.setter
def typeclass_path_set(self, value): def typeclass_path_set(self, value):
"Setter. Allows for self.typeclass_path = value" "Setter. Allows for self.typeclass_path = value"
self.db_typeclass_path = value self.db_typeclass_path = value
self.save() self.save()
SA(self, 'cached_typeclass_path', value) SA(self, '_cached_db_typeclass_path', value)
#@typeclass_path.deleter #@typeclass_path.deleter
def typeclass_path_del(self): def typeclass_path_del(self):
"Deleter. Allows for del self.typeclass_path" "Deleter. Allows for del self.typeclass_path"
self.db_typeclass_path = "" self.db_typeclass_path = ""
self.save() self.save()
self.cached_typeclass_path = "" DA(self, "_cached_db_typeclass_path")
typeclass_path = property(typeclass_path_get, typeclass_path_set, typeclass_path_del) typeclass_path = property(typeclass_path_get, typeclass_path_set, typeclass_path_del)
# date_created property # date_created property
#@property #@property
def date_created_get(self): def date_created_get(self):
"Getter. Allows for value = self.date_created" "Getter. Allows for value = self.date_created"
return self.db_date_created return get_cache(self, "date_created")
#@date_created.setter #@date_created.setter
def date_created_set(self, value): def date_created_set(self, value):
"Setter. Allows for self.date_created = value" "Setter. Allows for self.date_created = value"
@ -767,8 +760,9 @@ class TypedObject(SharedMemoryModel):
#@property #@property
def permissions_get(self): def permissions_get(self):
"Getter. Allows for value = self.name. Returns a list of permissions." "Getter. Allows for value = self.name. Returns a list of permissions."
if self.db_permissions: perms = get_cache(self, "permissions")
return [perm.strip() for perm in self.db_permissions.split(',')] if perms:
return [perm.strip() for perm in perms.split(',')]
return [] return []
#@permissions.setter #@permissions.setter
def permissions_set(self, value): def permissions_set(self, value):
@ -788,7 +782,7 @@ class TypedObject(SharedMemoryModel):
#@property #@property
def lock_storage_get(self): def lock_storage_get(self):
"Getter. Allows for value = self.lock_storage" "Getter. Allows for value = self.lock_storage"
return self.db_lock_storage return get_cache(self, "lock_storage")
#@lock_storage.setter #@lock_storage.setter
def lock_storage_set(self, value): def lock_storage_set(self, value):
"""Saves the lock_storagetodate. This is usually not called directly, but through self.lock()""" """Saves the lock_storagetodate. This is usually not called directly, but through self.lock()"""
@ -808,10 +802,7 @@ class TypedObject(SharedMemoryModel):
# #
# #
# Each subclass should set this property to their respective # these are identifiers for fast Attribute access and caching
# attribute model (ObjAttribute, PlayerAttribute etc).
#attribute_model_path = "src.typeclasses.models"
#attribute_model_name = "Attribute"
typeclass_paths = settings.OBJECT_TYPECLASS_PATHS typeclass_paths = settings.OBJECT_TYPECLASS_PATHS
attribute_class = Attribute # replaced by relevant attribute class for child attribute_class = Attribute # replaced by relevant attribute class for child
db_model_name = "typeclass" # used by attributes to safely store objects db_model_name = "typeclass" # used by attributes to safely store objects
@ -853,7 +844,7 @@ class TypedObject(SharedMemoryModel):
Alternetively, use obj.id directly to get dbref Alternetively, use obj.id directly to get dbref
without any #. without any #.
""" """
return "#%s" % str(self.id) return "#%s" % str(GA(self, "id"))
dbref = property(dbref_get) dbref = property(dbref_get)
# typeclass property # typeclass property
@ -871,10 +862,8 @@ class TypedObject(SharedMemoryModel):
the custom self.__getattribute__ more than necessary. the custom self.__getattribute__ more than necessary.
""" """
path = GA(self, "cached_typeclass_path") path = GA(self, "typeclass_path")
if not path: typeclass = GA(self, "_cached_typeclass")
path = GA(self, 'db_typeclass_path')
typeclass = GA(self, "cached_typeclass")
try: try:
if typeclass and GA(typeclass, "path") == path: if typeclass and GA(typeclass, "path") == path:
# don't call at_init() when returning from cache # don't call at_init() when returning from cache
@ -901,9 +890,9 @@ class TypedObject(SharedMemoryModel):
# we succeeded to import. Cache and return. # we succeeded to import. Cache and return.
SA(self, 'db_typeclass_path', tpath) SA(self, 'db_typeclass_path', tpath)
GA(self, 'save')() GA(self, 'save')()
SA(self, "cached_typeclass_path", tpath) SA(self, "_cached_db_typeclass_path", tpath)
typeclass = typeclass(self) typeclass = typeclass(self)
SA(self, "cached_typeclass", typeclass) SA(self, "_cached_typeclass", typeclass)
try: try:
typeclass.at_init() typeclass.at_init()
except Exception: except Exception:
@ -1017,9 +1006,9 @@ class TypedObject(SharedMemoryModel):
SA(self, 'db_typeclass_path', defpath) SA(self, 'db_typeclass_path', defpath)
GA(self, 'save')() GA(self, 'save')()
if cache: if cache:
SA(self, "cached_typeclass_path", defpath) SA(self, "_cached_db_typeclass_path", defpath)
SA(self, "cached_typeclass", typeclass) SA(self, "_cached_typeclass", typeclass)
try: try:
typeclass.at_init() typeclass.at_init()
except Exception: except Exception:
@ -1040,17 +1029,17 @@ class TypedObject(SharedMemoryModel):
parents. parents.
""" """
try: try:
typeclass = typeclass.path typeclass = GA(typeclass, "path")
except AttributeError: except AttributeError:
pass pass
typeclasses = [typeclass] + ["%s.%s" % (path, typeclass) for path in self.typeclass_paths] typeclasses = [typeclass] + ["%s.%s" % (path, typeclass) for path in GA(self, "typeclass_paths")]
if exact: if exact:
current_path = GA(self, "cached_typeclass_path") current_path = GA(self, "_cached_db_typeclass_path")
return typeclass and any([current_path == typec for typec in typeclasses]) return typeclass and any((current_path == typec for typec in typeclasses))
else: else:
# check parent chain # check parent chain
return any([cls for cls in self.typeclass.__class__.mro() return any((cls for cls in self.typeclass.__class__.mro()
if any(["%s.%s" % (cls.__module__, cls.__name__) == typec for typec in typeclasses])]) if any(("%s.%s" % (GA(cls,"__module__"), GA(cls,"__name__")) == typec for typec in typeclasses))))
# #
# Object manipulation methods # Object manipulation methods
@ -1101,13 +1090,13 @@ class TypedObject(SharedMemoryModel):
new_typeclass = self.typeclass new_typeclass = self.typeclass
if self.typeclass_path == new_typeclass.path: if self.typeclass_path == new_typeclass.path:
# the typeclass loading worked as expected # the typeclass loading worked as expected
self.cached_typeclass_path = None SA(self, "_cached_db_typeclass_path", None)
self.cached_typeclass = None SA(self, "_cached_typeclass", None)
elif no_default: elif no_default:
# something went wrong; the default was loaded instead, # something went wrong; the default was loaded instead,
# and we don't allow that; instead we return to previous. # and we don't allow that; instead we return to previous.
self.typeclass_path = old_typeclass_path SA(self, "typeclass_path", old_typeclass_path)
self.cached_typeclass = None SA(self, "_cached_typeclass", None)
return False return False
if clean_attributes: if clean_attributes:
@ -1147,7 +1136,7 @@ class TypedObject(SharedMemoryModel):
attribute_name: (str) The attribute's name. attribute_name: (str) The attribute's name.
""" """
return self.attribute_class.objects.filter(db_obj=self).filter( return GA(self, "attribute_class").objects.filter(db_obj=self).filter(
db_key__iexact=attribute_name).count() db_key__iexact=attribute_name).count()
def set_attribute(self, attribute_name, new_value=None): def set_attribute(self, attribute_name, new_value=None):
@ -1160,7 +1149,7 @@ class TypedObject(SharedMemoryModel):
a str, the object will be stored as a pickle. a str, the object will be stored as a pickle.
""" """
attrib_obj = None attrib_obj = None
attrclass = self.attribute_class attrclass = GA(self, "attribute_class")
try: try:
# use old attribute # use old attribute
attrib_obj = attrclass.objects.filter( attrib_obj = attrclass.objects.filter(

View file

@ -26,8 +26,7 @@ def is_iter(iterable):
def make_iter(obj): def make_iter(obj):
"Makes sure that the object is always iterable." "Makes sure that the object is always iterable."
if not hasattr(iterable, '__iter__'): if not hasattr(obj, '__iter__'): return [obj]
return [obj]
return obj return obj
def fill(text, width=78, indent=0): def fill(text, width=78, indent=0):