diff --git a/src/objects/models.py b/src/objects/models.py index f55dd54be6..8237bd0da2 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -306,27 +306,16 @@ class ObjectDB(TypedObject): del_field_cache(self, "sessid") sessid = property(__sessid_get, __sessid_set, __sessid_del) - # 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" + def _db_location_handler(self, new_value, old_value=None): + "This handles changes to the db_location field." + print "db_location_handler:", new_value, old_value 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 + old_loc = old_value + # new_value can be dbref, typeclass or dbmodel + if ObjectDB.objects.dbref(new_value, reqhash=False): + loc = ObjectDB.objects.dbref_search(new_value) + # this should not fail if new_value is valid. + loc = _GA(loc, "dbobj") # recursive location check def is_loc_loop(loc, depth=0): @@ -340,32 +329,85 @@ class ObjectDB(TypedObject): except RuntimeWarning: pass # set the location - set_field_cache(self, "location", loc) + _SA(self, "db_location", loc) # update the contents of each location if old_loc: - _GA(_GA(old_loc, "dbobj"), "contents_update")() + _GA(_GA(old_loc, "dbobj"), "contents_update")(self, remove=True) if loc: - _GA(loc, "contents_update")() + _GA(loc, "contents_update")(self) except RuntimeError: string = "Cannot set location, " - string += "%s.location = %s would create a location-loop." % (self.key, loc) + string += "%s.location = %s would create a location-loop." % (self.key, new_value) _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 + string += "%s is not a valid location." % new_value _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) + + ## 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 @@ -522,19 +564,26 @@ class ObjectDB(TypedObject): exclude = make_iter(exclude) if cont == None: cont = _GA(self, "contents_update")() - return [obj for obj in cont if obj not in exclude] + return [obj for obj in cont.values() if obj not in exclude] contents = property(contents_get) - def contents_update(self): + def contents_update(self, obj=None, remove=False): """ - Updates the contents property of the object with a new - object Called by - self.location_set. + Updates the contents property of the object - obj - - remove (true/false) - remove obj from content list + add - object to add to content list + remove object to remove from content list """ - cont = ObjectDB.objects.get_contents(self) + cont = get_prop_cache(self, "_contents") + if not cont: + cont = {} + if obj: + if remove: + cont.pop(self.dbid, None) + else: + cont[self.dbid] = obj + else: + cont = dict((o.dbid, o) for o in ObjectDB.objects.get_contents(self)) set_prop_cache(self, "_contents", cont) return cont diff --git a/src/server/caches.py b/src/server/caches.py index 27d2b5574c..9cbeb5bf4e 100644 --- a/src/server/caches.py +++ b/src/server/caches.py @@ -2,6 +2,8 @@ Central caching module. """ + +from collections import defaultdict from django.dispatch import Signal from django.core.cache import get_cache #from django.db.models.signals import pre_save, pre_delete, post_init @@ -18,12 +20,13 @@ _DA = object.__delattr__ _FIELD_CACHE = get_cache("field_cache") _ATTR_CACHE = get_cache("attr_cache") -_PROP_CACHE = get_cache("prop_cache") +#_PROP_CACHE = get_cache("prop_cache") +_PROP_CACHE = defaultdict(dict) # make sure caches are empty at startup _FIELD_CACHE.clear() _ATTR_CACHE.clear() -_PROP_CACHE.clear() +#_PROP_CACHE.clear() #------------------------------------------------------------ # Cache key hash generation @@ -106,7 +109,7 @@ def field_pre_save(sender, instance=None, update_fields=None, raw=False, **kwarg old_value = _FIELD_CACHE.get(hid) if hid else None # the handler may modify the stored value in various ways # don't catch exceptions, the handler must work! - new_value = handler(instance, new_value, oldval=old_value) + 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) if hid: @@ -170,24 +173,28 @@ def get_prop_cache(obj, propname): hid = hashid(obj, "-%s" % propname) if hid: #print "get_prop_cache", hid, propname, _PROP_CACHE.get(hid, None) - return _PROP_CACHE.get(hid, None) + return _PROP_CACHE[hid].get(propname, None) def set_prop_cache(obj, propname, propvalue): "Set property cache" hid = hashid(obj, "-%s" % propname) if hid: #print "set_prop_cache", propname, propvalue - _PROP_CACHE.set(hid, propvalue) + _PROP_CACHE[hid][propname] = propvalue + #_PROP_CACHE.set(hid, propvalue) def del_prop_cache(obj, propname): "Delete element from property cache" hid = hashid(obj, "-%s" % propname) - if hid: - _PROP_CACHE.delete(hid) + if hid and propname in _PROP_CACHE[hid]: + del _PROP_CACHE[hid][propname] + #_PROP_CACHE.delete(hid) def flush_prop_cache(): "Clear property cache" - _PROP_CACHE.clear() + global _PROP_CACHE + _PROP_CACHE = defaultdict(dict) + #_PROP_CACHE.clear() #_ENABLE_LOCAL_CACHES = settings.GAME_CACHE_TYPE @@ -491,7 +498,7 @@ def del_field_cache(obj, name): #def set_attr_cache(obj, attrname, attrobj): # pass #def del_attr_cache(obj, attrname): -# pass +# passk #def flush_attr_cache(obj=None): # pass diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index 24696c7881..a39860b898 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -474,34 +474,32 @@ class TypedObject(SharedMemoryModel): #@property def __name_get(self): "Getter. Allows for value = self.name" - return get_field_cache(self, "key") - #@name.setter + return self.key + #@name.sette def __name_set(self, value): "Setter. Allows for self.name = value" - set_field_cache(self, "key", value) + self.key = value #@name.deleter def __name_del(self): "Deleter. Allows for del self.name" raise Exception("Cannot delete name!") name = property(__name_get, __name_set, __name_del) - # typeclass_path property + # typeclass_path property - we don't cache this. #@property def __typeclass_path_get(self): "Getter. Allows for value = self.typeclass_path" - return get_field_cache(self, "typeclass_path") + return _GA(self, "db_typeclass_path")#get_field_cache(self, "typeclass_path") #@typeclass_path.setter def __typeclass_path_set(self, value): "Setter. Allows for self.typeclass_path = value" - set_field_cache(self, "typeclass_path", value) - _SA(self, "_cached_typeclass", None) + _SA(self, "db_typeclass_path", value) + _GA(self, "save")(update_fields=["db_typeclass_path"]) #@typeclass_path.deleter def __typeclass_path_del(self): "Deleter. Allows for del self.typeclass_path" self.db_typeclass_path = "" - self.save() - del_field_cache(self, "typeclass_path") - _SA(self, "_cached_typeclass", None) + _GA(self, "save")(update_fields=["db_typeclass_path"]) typeclass_path = property(__typeclass_path_get, __typeclass_path_set, __typeclass_path_del) # date_created property