[Zodb-checkins] CVS: ZODB3/ZEO - simul.py:1.4

Guido van Rossum guido@python.org
Fri, 6 Sep 2002 12:09:10 -0400


Update of /cvs-repository/ZODB3/ZEO
In directory cvs.zope.org:/tmp/cvs-serv5084

Modified Files:
	simul.py 
Log Message:
Refactored the classes, moving more infrastructure into the Simulation
base class.


=== ZODB3/ZEO/simul.py 1.3 => 1.4 ===
--- ZODB3/ZEO/simul.py:1.3	Fri Sep  6 11:31:01 2002
+++ ZODB3/ZEO/simul.py	Fri Sep  6 12:09:10 2002
@@ -80,52 +80,33 @@
 
 class Simulation:
 
-    """Abstract base class to define simulation interface.
+    """Base class for simulations.
 
-    These are the only methods that the driver program calls.
+    The driver program calls: event(), printheader(), finish().
 
-    The constructor signature is not part of the interface.
+    The standard event() method calls these additional methods:
+    write(), load(), inval(), report(), restart(); the standard
+    finish() method also calls report().
 
     """
 
-    def event(self, ts, dlen, version, code, current, oid, serial):
-        pass
-
-    def printheader(self):
-        pass
-
-    def finish(self):
-        pass
-
-class ZEOCacheSimulation(Simulation):
-
-    """Simulate the current (ZEO 1.0 and 2.0) ZEO cache behavior."""
-
-    def __init__(self, cachelimit):
-        # Store simulation parameters
-        self.filelimit = cachelimit / 2
+    def __init__(self):
         # Initialize global statistics
         self.epoch = None
-        self.total_flips = 0
         self.total_loads = 0
-        self.total_hits = 0
+        self.total_hits = 0 # Subclass must increment
         self.total_invals = 0
         self.total_writes = 0
-        # Reset per-run statistics and simulation data
+        # Reset per-run statistics and set up simulation data
         self.restart()
 
     def restart(self):
-        # Set up statistics
-        self.flips = 0
+        # Reset per-run statistics
         self.loads = 0
-        self.hits = 0
+        self.hits = 0 # Subclass must increment
         self.invals = 0
         self.writes = 0
         self.ts0 = None
-        # Set up simulation data
-        self.filesize = [4, 4] # account for magic number
-        self.fileoids = [{}, {}]
-        self.current = 0 # index into filesize, fileoids
 
     def event(self, ts, dlen, _version, code, _current, oid, _serial):
         # Record first and last timestamp seen
@@ -140,44 +121,98 @@
         # unless the object in fact did not exist).  Updates always write.
         if dlen and code & 0x70 in (0x20, 0x30, 0x50):
             if code == 0x3A:
+                # Update
                 self.writes += 1
                 self.total_writes += 1
+                self.write(oid, dlen)
             else:
+                # Load hit or store -- these are really the load requests
                 self.loads += 1
                 self.total_loads += 1
-            if code != 0x3A and (self.fileoids[self.current].get(oid) or
-                                 self.fileoids[1 - self.current].get(oid)):
-                self.hits += 1
-                self.total_hits += 1
-            else:
-                # Simulate a miss+store.  Fudge because dlen is
-                # rounded up to multiples of 256.  (31 is header
-                # overhead per cache record; 127 is to compensate for
-                # rounding up to multiples of 256.)
-                dlen = dlen + 31 - 127
-                if self.filesize[self.current] + dlen > self.filelimit:
-                    # Cache flip
-                    self.flips += 1
-                    self.total_flips += 1
-                    self.current = 1 - self.current
-                    self.filesize[self.current] = 4
-                    self.fileoids[self.current] = {}
-                self.filesize[self.current] += dlen
-                self.fileoids[self.current][oid] = 1
+                self.load(oid, dlen)
         elif code & 0x70 == 0x10:
             # Invalidate
-            if self.fileoids[self.current].get(oid):
-                self.invals += 1
-                self.total_invals += 1
-                del self.fileoids[self.current][oid]
-            elif self.fileoids[1 - self.current].get(oid):
-                self.invals += 1
-                self.total_invals += 1
-                del self.fileoids[1 - self.current][oid]
+            self.invals += 1
+            self.total_invals += 1
+            self.inval(oid)
         elif code == 0x00:
             # Restart
             self.report()
             self.restart()
+
+    def printheader(self):
+        pass
+
+    def write(self, oid, size):
+        pass
+
+    def load(self, oid, size):
+        pass
+
+    def inval(self, oid):
+        pass
+
+    def finish(self):
+        self.report()
+
+    def report(self):
+        pass
+
+class ZEOCacheSimulation(Simulation):
+
+    """Simulate the current (ZEO 1.0 and 2.0) ZEO cache behavior.
+
+    This assumes the cache is not persistent (we don't know how to
+    simulate cache validation.)
+
+    """
+
+    def __init__(self, cachelimit):
+        # Initialize base class
+        Simulation.__init__(self)
+        # Store simulation parameters
+        self.filelimit = cachelimit / 2
+        # Initialize additional global statistics
+        self.total_flips = 0
+
+    def restart(self):
+        # Reset base class
+        Simulation.restart(self)
+        # Reset additional per-run statistics
+        self.flips = 0
+        # Set up simulation
+        self.filesize = [4, 4] # account for magic number
+        self.fileoids = [{}, {}]
+        self.current = 0 # index into filesize, fileoids
+
+    def load(self, oid, size):
+        if (self.fileoids[self.current].get(oid) or
+            self.fileoids[1 - self.current].get(oid)):
+            self.hits += 1
+            self.total_hits += 1
+        else:
+            self.write(oid, size)
+
+    def write(self, oid, size):
+        # Fudge because size is rounded up to multiples of 256.  (31
+        # is header overhead per cache record; 127 is to compensate
+        # for rounding up to multiples of 256.)
+        size = size + 31 - 127
+        if self.filesize[self.current] + size > self.filelimit:
+            # Cache flip
+            self.flips += 1
+            self.total_flips += 1
+            self.current = 1 - self.current
+            self.filesize[self.current] = 4
+            self.fileoids[self.current] = {}
+        self.filesize[self.current] += size
+        self.fileoids[self.current][oid] = 1
+
+    def inval(self, oid):
+        if self.fileoids[self.current].get(oid):
+            del self.fileoids[self.current][oid]
+        elif self.fileoids[1 - self.current].get(oid):
+            del self.fileoids[1 - self.current][oid]
 
     format = "%12s %9s %8s %8s %6s %6s %5s %6s"