[1533] in Coldmud discussion meeting

root meeting help first previous next next in chain last in chain last

[patch] optimize method cache

daemon@ATHENA.MIT.EDU (Tue Dec 21 03:01:52 1999 )

From: bruce@puremagic.com
To: coldstuff@cold.org
Date: Mon, 20 Dec 1999 23:51:28 -0800 (PST)
Reply-To: coldstuff@cold.org

This is a patch to help optimize the method cache some.

It changes the following:

1) Do not invalidate the cache when destroying an object that has
   no methods and no children.  This'll prevent the method cache
   from getting nuked everytime someone connects as a user, or via
   the web interface.
2) When deleting a method, only invalidate if you actually do
   anything.  In any other case, why bother invalidating?
3) In setting the access on a method, only invalidate in the
   specific instance in which you need to invalidate.  Also,
   save some work and don't flag it as dirty unless you need to
   do so.

There are other optimizations left that could/should be made.  I had made
posts about this to the genesis@cold.org mailing list, nearly a year ago:

http://web.cold.org/messaging/genesis/msg00003.html
http://web.cold.org/messaging/genesis/msg00004.html

The stuff in there is still true.  The first fix above isn't optimal (for
reasons laid out below, but I don't feel like thinking about it that hard
tonight).

The other optimization that should be addressed and that was left out of
both of those emails, is that negative method lookups should be cached.
However, with the addition of that much extra information to the cache,
it is well past time for someone to look at adding monitoring data to the
various caches and tracking the hit/miss/overwrite rates to help people
tune their cache sizes.

 - Bruce

--- Genesis-1.1.8-STABLE/src/data/object.c	Tue Jul 13 13:47:30 1999
+++ Genesis/src/data/object.c	Mon Dec 20 23:30:07 1999
@@ -145,9 +145,19 @@
     cList *children;
     cData *d, cthis;
     Obj *kid;
+    Long has_methods = 0, i = 0;
 
-    /* Invalidate the method cache. */
-    cur_stamp++;
+    do {
+        if (object->methods.tab[i].m) {
+            has_methods = 1;
+        }
+	i++;
+    } while (!has_methods && (i < object->methods.size));
+
+    /* Invalidate the method cache if object is not a method-less leaf object */
+    if ((list_length(object->children) != 0 || (has_methods)) {
+        cur_stamp++;
+    }
 
     /* remove the object name, if it has one */
     object_del_objname(object);
@@ -1085,9 +1095,6 @@
 Int object_del_method(Obj *object, Long name) {
     Int *indp, ind;
 
-    /* Invalidate the method cache. */
-    cur_stamp++;
-
     /* This is the index-thread equivalent of double pointers in a standard
      * linked list.  We traverse the list using pointers to the ->next element
      * of the method pointers. */
@@ -1114,6 +1121,9 @@
 
 	    object->dirty = 1;
 
+	    /* Invalidate method cache */
+	    cur_stamp++;
+
 	    /* Return one, meaning the method was successfully deleted. */
 	    return 1;
 	}
@@ -1162,9 +1172,18 @@
     method = object_find_method_local(object, name, FROB_ANY);
     if (method == NULL)
         return -1;
+    if (method->m_access = access) {
+        /* yay, we don't have to do anything. let's go home. */
+        return access;
+    }
+    if ((method->m_access == MS_FROB) || (access == MS_FROB)) {
+        /*
+	 * only invalidate when changing to or from 'frob' access.
+	 */
+	cur_stamp++;
+    }
     method->m_access = access;
     object->dirty = 1;
-    cur_stamp++; /* to invalidate cached frob/!frob defaults */
     return access;
 }