[Zodb-checkins] CVS: ZODB3/Tools - zeoqueue.py:1.2

Jeremy Hylton jeremy@zope.com
Mon, 16 Dec 2002 13:45:58 -0500


Update of /cvs-repository/ZODB3/Tools
In directory cvs.zope.org:/tmp/cvs-serv21276

Modified Files:
	zeoqueue.py 
Log Message:
Apparently functional version that reads from the end.

Starts near the end of the file and reads forward, looking for a
complete snapshot.  If it doesn't find one, move farther from the end
and repeat.

XXX This approach does N**2 reads, where N is the number of times we
need to move further back and retry.  When we move backwards, we
double the distance from the end of the file.


=== ZODB3/Tools/zeoqueue.py 1.1 => 1.2 ===
--- ZODB3/Tools/zeoqueue.py:1.1	Mon Dec 16 13:26:12 2002
+++ ZODB3/Tools/zeoqueue.py	Mon Dec 16 13:45:58 2002
@@ -1,11 +1,14 @@
 #! /usr/bin/env python
 """Report on the number of currently waiting clients in the ZEO queue."""
 
-import fileinput
+import getopt
 import re
 import sys
 import time
 
+# pick arbitrary buffer size that isn't too big
+BUFSIZE = 8 * 1024 * 1024
+
 rx_time = re.compile('(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d)')
 
 def parse_time(line):
@@ -81,6 +84,15 @@
         self.t_restart = None
         self.txns = {}
 
+    def iscomplete(self):
+        # The status report will always be complete if we encounter an
+        # explicit restart.
+        if self.t_restart is not None:
+            return 1
+        # If we haven't seen a restart, assume that seeing a finished
+        # transaction is good enough.
+        return self.commit is not None
+
     def report(self):
         print "Blocked transactions:", self.n_blocked
         if not VERBOSE:
@@ -98,12 +110,13 @@
         L = [(txn.begin, txn) for txn in self.txns.values()]
         L.sort()
 
-        first_txn = L[0][1]
-        if first_txn.isactive():
-            began = first_txn.begin
-            print "Blocked transaction began at:", time.ctime(began)
-            print "Hint:", first_txn.hint
-            print "Idle time: %d sec" % int(time.time() - began)
+        for x, txn in L:
+            if txn.isactive():
+                began = txn.begin
+                print "Blocked transaction began at:", time.ctime(began)
+                print "Hint:", txn.hint
+                print "Idle time: %d sec" % int(time.time() - began)
+                break
 
     def process(self, line):
         if line.find("calling") != -1:
@@ -213,23 +226,38 @@
                 pass
         self.commit = self.commit_or_abort = txn
 
-def main():
-    global VERBOSE
-    # decide whether -v was passed on the command line
-    try:
-        i = sys.argv.index("-v")
-    except ValueError:
-        VERBOSE = 0
-    else:
-        VERBOSE = 1
-        # fileinput assumes all of sys.argv[1:] is files it should read
-        del sys.argv[i]
-
+def process_from(f, pos):
     s = Status()
-    for line in fileinput.input():
+    f.seek(-pos, 2)
+    f.readline()
+    for line in f.readlines(BUFSIZE):
         s.process(line)
-    s.report()
+    return s
 
+def main():
+    global VERBOSE
+    VERBOSE = 0
+    opts, args = getopt.getopt(sys.argv[1:], 'v')
+    for k, v in opts:
+        if k == '-v':
+            VERBOSE += 1
+
+    path = args[0]
+    f = open(path, "rb")
+
+    # Start at pos bytes from the end of the file and read forwards.
+    # If we read enough log data to have a complete snapshot of the
+    # server state, stop and print a report.  If not, move twice as
+    # far from the end of the file and repeat.
+    
+    pos = 16 * 1024
+    while 1:
+        s = process_from(f, pos)
+        if s.iscomplete():
+            break
+        pos *= 2
+    s.report()
+    
 if __name__ == "__main__":
     main()