From jeremy at zope.com Thu Aug 1 14:46:52 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/zrpc - connection.py:1.5 Message-ID: <200208011846.g71IkqS08736@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv8723 Modified Files: connection.py Log Message: Make doubly sure that SystemExit isn't caught be generic error handling. === ZODB3/ZEO/zrpc/connection.py 1.4 => 1.5 === meth = getattr(self.obj, name) try: ret = meth(*args) + except (SystemExit, KeyboardInterrupt): + raise except Exception, msg: - error = sys.exc_info()[:2] - log("%s() raised exception: %s" % (name, msg), - zLOG.ERROR, error=sys.exc_info()) - return self.return_error(msgid, flags, error[0], error[1]) + error = sys.exc_info() + log("%s() raised exception: %s" % (name, msg), zLOG.ERROR, + error=error) + error = error[:2] + return self.return_error(msgid, flags, *error) if flags & ASYNC: if ret is not None: @@ -186,7 +189,9 @@ self.send_reply(msgid, ret) def handle_error(self): - self.log_error() + if sys.exc_info()[0] == SystemExit: + raise sys.exc_info() + self.log_error("Error caught in asyncore") self.close() def log_error(self, msg="No error message supplied"): From jeremy at zope.com Thu Aug 1 14:50:29 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/tests - testStart.py:1.1 Message-ID: <200208011850.g71IoTQ10507@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv10481/tests Added Files: testStart.py Log Message: Factor out some startup code to util module. Add a couple of simple tests that make sure that start.py script runs. The tests are meager -- most of the possible arguments are untested -- and only run on Unix. === Added File ZODB3/ZEO/tests/testStart.py === ############################################################################## # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import os import signal import sys import tempfile import time import unittest import ZEO.start from ZEO.ClientStorage import ClientStorage from ZEO.util import Environment class StartTests(unittest.TestCase): cmd = "%s %s" % (sys.executable, ZEO.start.__file__) if cmd[-1] == "c": cmd = cmd[:-1] def setUp(self): self.pids = {} self.env = Environment(self.cmd) def tearDown(self): try: self.stop_server() self.shutdown() finally: for ext in "", ".index", ".tmp", ".lock", ".old": f = "Data.fs" + ext try: os.remove(f) except os.error: pass try: os.remove(self.env.zeo_pid) except os.error: pass def stop_server(self): if not os.path.exists(self.env.zeo_pid): # If there's no pid file, assume the server isn't running return ppid, pid = map(int, open(self.env.zeo_pid).read().split()) self.kill(pids=[pid]) def kill(self, sig=signal.SIGTERM, pids=None): if pids is None: pids = self.pids for pid in pids: try: os.kill(pid, sig) except os.error, err: print err def wait(self, flag=0, pids=None): if pids is None: pids = self.pids alive = [] for pid in self.pids: try: _pid, status = os.waitpid(pid, flag) except os.error, err: if err[0] == 10: continue print err else: if status == 0: alive.append(pid) return alive def shutdown(self): # XXX This is probably too complicated, but I'm not sure what # the right thing to do is. alive = self.wait(os.WNOHANG) if not alive: return self.kill(pids=alive) alive = self.wait(os.WNOHANG, alive) if not alive: return self.kill(signal.SIGKILL, pids=alive) alive = self.wait(pids=alive) def fork(self, *args): file = tempfile.mktemp() pid = os.fork() if pid: self.pids[pid] = file return file else: try: f = os.popen(self.cmd + " " + " ".join(args)) buf = f.read() f.close() f = open(file, "wb") f.write(buf) f.close() finally: os._exit(0) def system(self, *args): file = self.fork(*args) self.wait() f = open(file, "rb") buf = f.read() f.close() return buf def connect(self, port=None, wait=1): cs = ClientStorage(('', port), wait=wait) cs.close() def testNoPort(self): outp = self.system("-s") self.assert_(outp.find("No port specified") != -1) def testStart(self): port = 9090 outp = self.fork("-s", "-p", str(port)) self.connect(port=port) def test_suite(): if os.name == "posix": return unittest.makeSuite(StartTests) else: # Don't even bother with these tests on Windows return None From jeremy at zope.com Thu Aug 1 14:50:29 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - util.py:1.1 start.py:1.38 Message-ID: <200208011850.g71IoTi10502@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv10481 Modified Files: start.py Added Files: util.py Log Message: Factor out some startup code to util module. Add a couple of simple tests that make sure that start.py script runs. The tests are meager -- most of the possible arguments are untested -- and only run on Unix. === Added File ZODB3/ZEO/util.py === ############################################################################## # # Copyright (c) 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """Utilities for setting up the server environment.""" import os def parentdir(p, n=1): """Return the parent of p, n levels up.""" d = p while n: d = os.path.split(d)[0] if not d or d == '.': d = os.getcwd() n -= 1 return d class Environment: def __init__(self, argv0): v = os.environ.get("INSTANCE_HOME") if v is None: # looking for a Zope/var directory assuming that this code # is installed in Zope/lib/python/ZEO p = parentdir(argv0, 4) if os.path.isdir(os.path.join(p, "var")): v = p else: v = os.getcwd() self.home = v self.var = os.path.join(v, "var") if not os.path.isdir(self.var): self.var = self.home pid = os.environ.get("ZEO_SERVER_PID") if pid is None: pid = os.path.join(v, "ZEO_SERVER.pid") self.zeo_pid = pid self.fs = os.path.join(self.var, "Data.fs") === ZODB3/ZEO/start.py 1.37 => 1.38 === return d def get_storage(m, n, cache={}): - p=sys.path + p = sys.path d, m = os.path.split(m) if m.endswith('.py'): m = m[:-3] @@ -102,6 +102,8 @@ global LOG, INFO, ERROR from zLOG import LOG, INFO, ERROR, PANIC + from ZEO.util import Environment + env = Environment(me) # XXX hack for profiling support global unix, storages, zeo_pid, asyncore @@ -116,23 +118,6 @@ args.append(a) last = a - if os.environ.has_key('INSTANCE_HOME'): - INSTANCE_HOME = os.environ['INSTANCE_HOME'] - elif os.path.isdir(os.path.join(directory(me, 4),'var')): - INSTANCE_HOME = directory(me, 4) - else: - INSTANCE_HOME = os.getcwd() - - if os.path.isdir(os.path.join(INSTANCE_HOME, 'var')): - var = os.path.join(INSTANCE_HOME, 'var') - else: - var = INSTANCE_HOME - - zeo_pid = os.environ.get('ZEO_SERVER_PID', - os.path.join(var, 'ZEO_SERVER.pid')) - - fs = os.path.join(var, 'Data.fs') - usage="""%s [options] [filename] where options are: @@ -175,7 +160,7 @@ -s flag. if no file name is specified, then %s is used. - """ % (me, fs) + """ % (me, env.fs) try: opts, args = getopt.getopt(args, 'p:Dh:U:sS:u:P:d') @@ -192,6 +177,7 @@ UID = 'nobody' prof = None detailed = 0 + fs = None for o, v in opts: if o =='-p': port = int(v) @@ -225,7 +211,6 @@ sys.exit(1) fs = args[0] -## __builtins__.__debug__ = debug if debug: os.environ['Z_DEBUG_MODE'] = '1' if detailed: @@ -259,8 +244,8 @@ storages[n]=get_storage(m,a) if not storages: - import ZODB.FileStorage - storages['1']=ZODB.FileStorage.FileStorage(fs) + from ZODB.FileStorage import FileStorage + storages['1'] = FileStorage(fs or env.fs) # Try to set up a signal handler setup_signals(storages) @@ -280,7 +265,7 @@ except: pass # getpid not supported else: - open(zeo_pid,'w').write("%s %s" % (ppid, pid)) + open(env.zeo_pid,'w').write("%s %s" % (ppid, pid)) except: # Log startup exception and tell zdaemon not to restart us. @@ -324,6 +309,7 @@ signal.signal(signal.SIGHUP, rotate_logs_handler) def shutdown(storages, die=1): + LOG("ZEO Server", INFO, "Received signal") import asyncore # Do this twice, in case we got some more connections @@ -343,7 +329,6 @@ pass try: - from zLOG import LOG, INFO s = die and "shutdown" or "restart" LOG('ZEO Server', INFO, "Shutting down (%s)" % s) except: From jeremy at zope.com Thu Aug 1 15:15:43 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.42 Message-ID: <200208011915.g71JFh018167@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv18147 Modified Files: ClientStorage.py Log Message: Use None instead of '' as the default. === ZODB3/ZEO/ClientStorage.py 1.41 => 1.42 === class ClientStorage: def __init__(self, addr, storage='1', cache_size=20000000, - name='', client='', var=None, + name='', client=None, var=None, min_disconnect_poll=5, max_disconnect_poll=300, wait=0, read_only=0): @@ -88,7 +88,7 @@ self._basic_init(name or str(addr)) # Decide whether to use non-temporary files - client = client or os.environ.get('ZEO_CLIENT', '') + client = client or os.environ.get('ZEO_CLIENT') self._cache = ClientCache.ClientCache(storage, cache_size, client=client, var=var) self._cache.open() # XXX open now? or later? From jeremy at zope.com Thu Aug 1 15:16:18 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientCache.py:1.24 Message-ID: <200208011916.g71JGIU18501@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv18489 Modified Files: ClientCache.py Log Message: test client against None. === ZODB3/ZEO/ClientCache.py 1.23 => 1.24 === self._acquire = L.acquire self._release = L.release - if client: + if client is not None: # Create a persistent cache if var is None: try: From jeremy at zope.com Thu Aug 1 15:25:33 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientCache.py:1.25 Message-ID: <200208011925.g71JPXw21275@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv21258 Modified Files: ClientCache.py Log Message: Generate cache file names in a more straightforward way. === ZODB3/ZEO/ClientCache.py 1.24 => 1.25 === var = os.getcwd() # Get the list of cache file names - self._p = p = map(lambda i, p=storage, var=var, c=client: - os.path.join(var, 'c%s-%s-%s.zec' % (p, c, i)), - (0, 1)) + fmt = os.path.join(var, "c%s-%s-%%s.zec" % (storage, client)) + self._p = p = [fmt % 0, fmt % 1] # get the list of cache files self._f = f = [None, None] From jeremy at zope.com Thu Aug 1 15:28:19 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientCache.py:1.26 Message-ID: <200208011928.g71JSJf22143@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv22132 Modified Files: ClientCache.py Log Message: Comment twiddling. === ZODB3/ZEO/ClientCache.py 1.25 => 1.26 === except: var = os.getcwd() - # Get the list of cache file names fmt = os.path.join(var, "c%s-%s-%%s.zec" % (storage, client)) + # Initialize pairs of filenames, file objects, and serialnos. self._p = p = [fmt % 0, fmt % 1] - # get the list of cache files self._f = f = [None, None] - - # initialize cache serial numbers - s=['\0\0\0\0\0\0\0\0', '\0\0\0\0\0\0\0\0'] + s = ['\0\0\0\0\0\0\0\0', '\0\0\0\0\0\0\0\0'] for i in 0, 1: if os.path.exists(p[i]): fi = open(p[i],'r+b') From jeremy at zope.com Mon Aug 5 14:32:54 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - __init__.py:1.7.6.1.2.3 Message-ID: <200208051832.g75IWsW17013@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv17000 Modified Files: Tag: ZEO2-branch __init__.py Log Message: As suggested by Barry. === ZEO/ZEO/__init__.py 1.7.6.1.2.2 => 1.7.6.1.2.3 === # FOR A PARTICULAR PURPOSE # ############################################################################## + +version = "2.0b1" From jeremy at zope.com Mon Aug 5 14:33:30 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - version.txt:1.1.2.2 Message-ID: <200208051833.g75IXU317195@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv17179 Modified Files: Tag: ZEO2-branch version.txt Log Message: Bump version in anticipation of release. === ZEO/ZEO/version.txt 1.1.2.1 => 1.1.2.2 === -2.0a1 +2.0b1 + From jeremy at zope.com Mon Aug 5 14:55:16 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - StorageServer.py:1.32.6.3.2.8 Message-ID: <200208051855.g75ItGj20890@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv20875 Modified Files: Tag: ZEO2-branch StorageServer.py Log Message: Fix reference to storage in slog(). (Should not use self.) === ZEO/ZEO/StorageServer.py 1.32.6.3.2.7 => 1.32.6.3.2.8 === def slog(storage, msg, level=zLOG.INFO, error=None, pid=os.getpid()): name = getattr(storage, '__name__', None) if name is None: - name = str(self.storage) + name = str(storage) zLOG.LOG("ZEO Server:%s:%s" % (pid, name), level, msg, error=error) class StorageServerError(StorageError): From jeremy at zope.com Mon Aug 5 14:57:22 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO - CHANGES.txt:1.28.2.2 Message-ID: <200208051857.g75IvM121371@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv21362 Modified Files: Tag: ZEO2-branch CHANGES.txt Log Message: Summary of changes since 2.0a1. === ZEO/CHANGES.txt 1.28.2.1 => 1.28.2.2 === Revision History, Zope Enterprise Objects, version 2 + ZEO 2.0 beta 1 + + The changes since ZEO 2.0a1 release are: + + - Added version identification. + + The variable ZEO.version is a string identifying the version + in the style of sys.version. The same string is also + available in ZEO/version.txt for people who want to check + without loading the code. + + - Fixed performance problem. + + The low-level socket code was often calling send() with very + small strings instead of joining them together before calling + send. The small string variant ran afoul of the Nagle + algorithm and delayed TCP acks. + + - Very long log messages avoided. + + Some of the logging messages at BLATHER and lower were + producing very long log messages because they included + all the argument of method calls, even when the argument + was a list with thousands of elements. These log messages + are now truncated at a reasonable length. + + - Fixed problem handling signals. + + The asyncore and zrpc error handlers would trap SystemExit + if it was raised by a signal handler. They now ignore it. + + - Fix bug in history(). + + The history() implementation prevent the client from returning + more than one item. + + - Enhanced logging for blocked transactions. + + If a transaction had to be blocked because another transaction + was executing, the server would log an info message. Now it + also logs a message when the transaction is resumed, so that + it doesn't look like the transaction was blocked forever. + + - Fixed bug in logging call for store(). + + The logging call could raise NameError. + + - Removed debug argument to ClientStorage constructor. + + It had no effect. + + - Added minimal tests of start.py. + + There are only run on Unix. + ZEO 2.0 alpha 1 Brief overview of the differences between ZEO 1.0 and 2.0. From jeremy at zope.com Mon Aug 5 15:09:54 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO - CHANGES.txt:1.30 Message-ID: <200208051909.g75J9sj23773@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv23760 Modified Files: CHANGES.txt Log Message: Commit changes accidentally made on the defunct ZEO2-branch. === ZEO/CHANGES.txt 1.29 => 1.30 === Revision History, Zope Enterprise Objects, version 2 + ZEO 2.0 beta 1 + + The changes since ZEO 2.0a1 release are: + + - Added version identification. + + The variable ZEO.version is a string identifying the version + in the style of sys.version. The same string is also + available in ZEO/version.txt for people who want to check + without loading the code. + + - Fixed performance problem. + + The low-level socket code was often calling send() with very + small strings instead of joining them together before calling + send. The small string variant ran afoul of the Nagle + algorithm and delayed TCP acks. + + - Very long log messages avoided. + + Some of the logging messages at BLATHER and lower were + producing very long log messages because they included + all the argument of method calls, even when the argument + was a list with thousands of elements. These log messages + are now truncated at a reasonable length. + + - Fixed problem handling signals. + + The asyncore and zrpc error handlers would trap SystemExit + if it was raised by a signal handler. They now ignore it. + + - Fix bug in history(). + + The history() implementation prevent the client from returning + more than one item. + + - Enhanced logging for blocked transactions. + + If a transaction had to be blocked because another transaction + was executing, the server would log an info message. Now it + also logs a message when the transaction is resumed, so that + it doesn't look like the transaction was blocked forever. + + - Fixed bug in logging call for store(). + + The logging call could raise NameError. + + - Removed debug argument to ClientStorage constructor. + + It had no effect. + + - Added minimal tests of start.py. + + There are only run on Unix. + ZEO 2.0 alpha 1 Brief overview of the differences between ZEO 1.0 and 2.0. From jeremy at zope.com Mon Aug 5 15:09:55 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - __init__.py:1.10 version.txt:1.3 Message-ID: <200208051909.g75J9tb23785@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv23760/ZEO Modified Files: __init__.py version.txt Log Message: Commit changes accidentally made on the defunct ZEO2-branch. === ZEO/ZEO/__init__.py 1.9 => 1.10 === # FOR A PARTICULAR PURPOSE # ############################################################################## + +version = "2.0b1" === ZEO/ZEO/version.txt 1.2 => 1.3 === -2.0a1 +2.0b1 From jeremy at zope.com Mon Aug 5 15:57:56 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testStart.py:1.2 Message-ID: <200208051957.g75JvuV32162@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv32151 Modified Files: testStart.py Log Message: Call keys() on dict. It won't be iterable until 2.3. === StandaloneZODB/ZEO/tests/testStart.py 1.1 => 1.2 === def kill(self, sig=signal.SIGTERM, pids=None): if pids is None: - pids = self.pids + pids = self.pids.keys() for pid in pids: try: os.kill(pid, sig) @@ -67,9 +67,9 @@ def wait(self, flag=0, pids=None): if pids is None: - pids = self.pids + pids = self.pids.keys() alive = [] - for pid in self.pids: + for pid in pids: try: _pid, status = os.waitpid(pid, flag) except os.error, err: From jeremy at zope.com Mon Aug 5 17:39:03 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - start.py:1.39 Message-ID: <200208052139.g75Ld3620494@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv20432/ZEO Modified Files: start.py Log Message: Attempt to fix log file rotation. No log writer that I know of has a reinitialize() function. zLOG has an initialize() function, but it isn't easy to get at yet. === StandaloneZODB/ZEO/start.py 1.38 => 1.39 === def rotate_logs(): import zLOG - if hasattr(zLOG.log_write, 'reinitialize'): - zLOG.log_write.reinitialize() - else: - # Hm, lets at least try to take care of the stupid logger: - zLOG._stupid_dest=None + init = getattr(zLOG, 'initialize', None) + if init is not None: + init() def rotate_logs_handler(signum, frame): rotate_logs() From jeremy at zope.com Mon Aug 5 17:44:22 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - start.py:1.40 Message-ID: <200208052144.g75LiM021524@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv21511 Modified Files: start.py Log Message: Make log rotation code work with a wider range of zLOG versions. === StandaloneZODB/ZEO/start.py 1.39 => 1.40 === def rotate_logs(): import zLOG + # There hasn't been a clear way to reinitialize the MinimalLogger. + # I'll checkin the public initialize() method soon, but also try some + # other strategies for older Zope installs :-(. init = getattr(zLOG, 'initialize', None) if init is not None: init() + return + # This will work if the minimal logger is in use, but not if some + # other logger is active. + import zLog.MinimalLogger + zLog.MinimalLogger._log.initialize() def rotate_logs_handler(signum, frame): rotate_logs() From jeremy at zope.com Mon Aug 5 17:55:56 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - CommitLockTests.py:1.3 Message-ID: <200208052155.g75LtuU23713@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv23702 Modified Files: CommitLockTests.py Log Message: Attempt to be more robust about unstoppable worker threads. Mark each WorkerThread as a daemon. Attempt to join() it when the test exits, but do so with a timeout. If, after the join(), the thread is still alive, mark the test as failed. Since it's just a daemon thread, the test program should still exit. === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.2 => 1.3 === self.trans = trans self.method = method threading.Thread.__init__(self) + self.setDaemon(True) def run(self): try: self.storage.tpc_begin(self.trans) oid = self.storage.new_oid() - self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', self.trans) + p = zodb_pickle(MinPO("c")) + self.storage.store(oid, ZERO, p, '', self.trans) oid = self.storage.new_oid() - self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', self.trans) + p = zodb_pickle(MinPO("c")) + self.storage.store(oid, ZERO, p, '', self.trans) self.storage.tpc_vote(self.trans) if self.method == "tpc_finish": self.storage.tpc_finish(self.trans) @@ -154,7 +157,9 @@ def _dowork2(self, method_name): for t in self._threads: - t.join() + t.join(10) + for t in self._threads: + self.failIf(t.isAlive()) def _duplicate_client(self): "Open another ClientStorage to the same server." From jeremy at zope.com Mon Aug 5 18:31:25 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testStart.py:1.3 Message-ID: <200208052231.g75MVPQ29122@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv29109/tests Modified Files: testStart.py Log Message: Add a primitive test of zLOG re-initialization. XXX This will probably hang for Guido. === StandaloneZODB/ZEO/tests/testStart.py 1.2 => 1.3 === except os.error: pass - def stop_server(self): + def getpids(self): if not os.path.exists(self.env.zeo_pid): # If there's no pid file, assume the server isn't running - return - ppid, pid = map(int, open(self.env.zeo_pid).read().split()) + return None, None + return map(int, open(self.env.zeo_pid).read().split()) + + def stop_server(self): + ppid, pid = self.getpids() self.kill(pids=[pid]) def kill(self, sig=signal.SIGTERM, pids=None): @@ -131,6 +134,35 @@ port = 9090 outp = self.fork("-s", "-p", str(port)) self.connect(port=port) + + def testLogRestart(self): + port = 9090 + logfile1 = tempfile.mktemp(suffix="log") + logfile2 = tempfile.mktemp(suffix="log") + os.environ["EVENT_LOG_FILE"] = logfile1 + + try: + outp = self.fork("-s", "-p", str(port)) + self.connect(port=port) + buf1 = open(logfile1).read() + self.assert_(buf1) + os.rename(logfile1, logfile2) + ppid, pid = self.getpids() + ## os.kill(ppid, signal.SIGHUP) + os.kill(pid, signal.SIGHUP) + self.connect(port=port) + buf2 = open(logfile1).read() + self.assert_(buf2) + finally: + self.shutdown() + try: + os.unlink(logfile1) + except os.error: + pass + try: + os.unlink(logfile2) + except os.error: + pass def test_suite(): if os.name == "posix": From jeremy at zope.com Mon Aug 5 18:32:54 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - CommitLockTests.py:1.4 Message-ID: <200208052232.g75MWs429312@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv29301 Modified Files: CommitLockTests.py Log Message: Oops. Use 1 for Python 2.1 compatibility. === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.3 => 1.4 === self.trans = trans self.method = method threading.Thread.__init__(self) - self.setDaemon(True) + self.setDaemon(1) def run(self): try: From jeremy at zope.com Tue Aug 6 10:59:24 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testStart.py:1.4 Message-ID: <200208061459.g76ExOq31852@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv31839 Modified Files: testStart.py Log Message: If there is no pid, there is nothing to kill. === StandaloneZODB/ZEO/tests/testStart.py 1.3 => 1.4 === def stop_server(self): ppid, pid = self.getpids() + if ppid is None: + return self.kill(pids=[pid]) def kill(self, sig=signal.SIGTERM, pids=None): From jeremy at zope.com Tue Aug 6 12:35:35 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - ThreadTests.py:1.3 Message-ID: <200208061635.g76GZZL15048@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv15037 Modified Files: ThreadTests.py Log Message: Override join() to provide a timeout. === StandaloneZODB/ZEO/tests/ThreadTests.py 1.2 => 1.3 === self.gotValueError = 0 self.gotDisconnected = 0 threading.Thread.__init__(self) + self.setDaemon(1) + + def join(self): + threading.Thread.join(self, 10) + assert not self.isAlive() class GetsThroughVoteThread(BasicThread): From jeremy at zope.com Tue Aug 6 19:09:21 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - client.py:1.5 Message-ID: <200208062309.g76N9Lw32558@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv32547/ZEO/zrpc Modified Files: client.py Log Message: Make thread join robust against runaways. === StandaloneZODB/ZEO/zrpc/client.py 1.4 => 1.5 === if self._thread is not None: # XXX race on _thread self._thread.stop() - self._thread.join() + self._thread.join(30) + assert not self._thread.isAlive() finally: self._connect_lock.release() if self.connection: From jeremy at zope.com Tue Aug 6 19:10:31 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.6 Message-ID: <200208062310.g76NAVc32679@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv32668/ZEO/zrpc Modified Files: connection.py Log Message: Add MTDelay() that blocks reply() on an event until send_reply() is ready. Add a poll call in send_reply() so that synchronous calls made when there is no other traffic don't cause long delays. (This probably only occurs during the pack tests.) === StandaloneZODB/ZEO/zrpc/connection.py 1.5 => 1.6 === def reply(self, obj): self.send_reply(self.msgid, obj) +class MTDelay(Delay): + + def __init__(self): + self.ready = threading.Event() + + def set_sender(self, msgid, send_reply): + Delay.set_sender(self, msgid, send_reply) + self.ready.set() + + def reply(self, obj): + self.ready.wait() + Delay.reply(self, obj) + class Connection(smac.SizedMessageAsyncConnection): """Dispatcher for RPC on object on both sides of socket. @@ -206,6 +219,7 @@ def send_reply(self, msgid, ret): msg = self.marshal.encode(msgid, 0, REPLY, ret) self.message_output(msg) + self._do_async_poll() def return_error(self, msgid, flags, err_type, err_value): if flags is None: From jeremy at zope.com Tue Aug 6 19:11:09 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.40 Message-ID: <200208062311.g76NB9200331@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv320/ZEO Modified Files: StorageServer.py Log Message: Fix pack(wait=1) implementation so that it actually waits. === StandaloneZODB/ZEO/StorageServer.py 1.39 => 1.40 === from ZEO import ClientStub from ZEO.CommitLog import CommitLog from ZEO.zrpc.server import Dispatcher -from ZEO.zrpc.connection import ManagedServerConnection, Delay +from ZEO.zrpc.connection import ManagedServerConnection, Delay, MTDelay import zLOG from ZODB.POSException import StorageError, StorageTransactionError, \ @@ -238,25 +238,30 @@ def modifiedInVersion(self, oid): return self.__storage.modifiedInVersion(oid) - def pack(self, t, wait=0): + def pack(self, t, wait=None): + if wait is not None: + wait = MTDelay() t = threading.Thread(target=self._pack, args=(t, wait)) t.start() + if wait is not None: + return wait - def _pack(self, t, wait=0): + def _pack(self, t, delay): try: self.__storage.pack(t, referencesf) except: self._log('Pack failed for %s' % self.__storage_id, zLOG.ERROR, error=sys.exc_info()) - if wait: + if delay is not None: raise else: - # XXX Why doesn't we broadcast on wait? - if not wait: + if delay is None: # Broadcast new size statistics self.server.invalidate(0, self.__storage_id, (), self.get_size_info()) + else: + delay.reply(None) def new_oids(self, n=100): """Return a sequence of n new oids, where n defaults to 100""" From jeremy at zope.com Thu Aug 8 14:25:11 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testStart.py:1.5 testZEO.py:1.26 Message-ID: <200208081825.g78IPBP17947@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv17911/ZEO/tests Modified Files: testStart.py testZEO.py Log Message: Refactor test cleanup to use removefs() helper function. StorageTestBase.removefs() will attempt to remove files with all the possible extensions that FileStorage will create. It will raise os.error for any error except ENOENT. Remove many variants of removefs() implemented in the various test suites. === StandaloneZODB/ZEO/tests/testStart.py 1.4 => 1.5 === --- StandaloneZODB/ZEO/tests/testStart.py:1.4 Tue Aug 6 10:59:23 2002 +++ StandaloneZODB/ZEO/tests/testStart.py Thu Aug 8 14:25:10 2002 @@ -22,6 +22,7 @@ import ZEO.start from ZEO.ClientStorage import ClientStorage from ZEO.util import Environment +from ZODB.tests.StorageTestBase import removefs class StartTests(unittest.TestCase): @@ -38,12 +39,7 @@ self.stop_server() self.shutdown() finally: - for ext in "", ".index", ".tmp", ".lock", ".old": - f = "Data.fs" + ext - try: - os.remove(f) - except os.error: - pass + removefs("Data.fs") try: os.remove(self.env.zeo_pid) except os.error: === StandaloneZODB/ZEO/tests/testZEO.py 1.25 => 1.26 === --- StandaloneZODB/ZEO/tests/testZEO.py:1.25 Tue Jun 11 09:43:06 2002 +++ StandaloneZODB/ZEO/tests/testZEO.py Thu Aug 8 14:25:10 2002 @@ -29,7 +29,7 @@ import ThreadedAsync, ZEO.trigger from ZODB.FileStorage import FileStorage from ZODB.Transaction import Transaction -from ZODB.tests.StorageTestBase import zodb_pickle, MinPO +from ZODB.tests.StorageTestBase import zodb_pickle, MinPO, removefs import zLOG from ZEO.tests import forker, Cache, CommitLockTests, ThreadTests @@ -149,13 +149,7 @@ return 'FileStorage', (self.__fs_base, '1') def delStorage(self): - # file storage appears to create four files - for ext in '', '.index', '.lock', '.tmp', '.old': - path = self.__fs_base + ext - try: - os.remove(path) - except os.error: - pass + removefs(self.__fs_base) class WindowsGenericTests(GenericTests): """Subclass to support server creation on Windows. @@ -192,13 +186,7 @@ return 'FileStorage', (self.__fs_base, '1') # create=1 def delStorage(self): - # file storage appears to create four files - for ext in '', '.index', '.lock', '.tmp': - path = self.__fs_base + ext - try: - os.remove(path) - except os.error: - pass + removefs(self.__fs_base) class ConnectionTests(StorageTestBase.StorageTestBase): """Tests that explicitly manage the server process. From jeremy at zope.com Fri Aug 9 16:07:30 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - client.py:1.1.2.2.2.3 Message-ID: <200208092007.g79K7UM10693@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv10589/ZEO/zrpc Modified Files: Tag: ZEO2-branch client.py Log Message: Log symbolic constants with connect_ex() (and log at DEBUG level). XXX Add timeout to join() call in thread cleanup. === StandaloneZODB/ZEO/zrpc/client.py 1.1.2.2.2.2 => 1.1.2.2.2.3 === --- StandaloneZODB/ZEO/zrpc/client.py:1.1.2.2.2.2 Thu May 30 23:19:16 2002 +++ StandaloneZODB/ZEO/zrpc/client.py Fri Aug 9 16:07:29 2002 @@ -87,7 +87,9 @@ if self._thread is not None: # XXX race on _thread self._thread.stop() - self._thread.join() + self._thread.join(10) + if self._thread.isAlive(): + print "Warning! Thread still alive" finally: self._connect_lock.release() if self.connection: @@ -314,7 +316,8 @@ log("failed to connect to %s: %s" % (addr, msg), level=zLOG.ERROR) else: - log("connect_ex(%s) == %s" % (addr, e)) + log("connect_ex(%s) == %s" % (addr, errno.errorcode.get(e, e)), + level=zLOG.DEBUG) if e in _CONNECT_IN_PROGRESS: return elif e in _CONNECT_OK: From jeremy at zope.com Fri Aug 9 16:09:04 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - TestThread.py:1.1.2.1 CommitLockTests.py:1.1.2.6 Message-ID: <200208092009.g79K94510918@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv10805/tests Modified Files: Tag: ZEO2-branch CommitLockTests.py Added Files: Tag: ZEO2-branch TestThread.py Log Message: Add TestThread class that causes test to fail if it doesn't exit, but doesn't cause the tests to hang on exit with unstopped threads. Use TestThread in CommitLockTests. === Added File StandaloneZODB/ZEO/tests/TestThread.py === ############################################################################## # # Copyright (c) 2002 Zope Corporation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """A Thread base class for use with unittest.""" from cStringIO import StringIO import threading import traceback class TestThread(threading.Thread): __super_init = threading.Thread.__init__ __super_run = threading.Thread.run def __init__(self, testcase, group=None, target=None, name=None, args=(), kwargs={}, verbose=None): self.__super_init(group, target, name, args, kwargs, verbose) self.setDaemon(1) self._testcase = testcase def run(self): try: self.testrun() except Exception, err: s = StringIO() traceback.print_exc(file=s) self._testcase.fail("Exception in thread %s:\n%s\n" % (self, s.getvalue())) def cleanup(self, timeout=15): self.join(timeout) if self.isAlive(): self._testcase.fail("Thread did not finish: %s" % self) === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.1.2.5 => 1.1.2.6 === --- StandaloneZODB/ZEO/tests/CommitLockTests.py:1.1.2.5 Tue May 21 18:28:57 2002 +++ StandaloneZODB/ZEO/tests/CommitLockTests.py Fri Aug 9 16:09:03 2002 @@ -17,6 +17,7 @@ from ZODB.Transaction import Transaction from ZODB.tests.StorageTestBase import zodb_pickle, MinPO +from ZEO.tests.TestThread import TestThread import ZEO.ClientStorage from ZEO.Exceptions import Disconnected @@ -27,30 +28,32 @@ def invalidate(self, *args): pass -class WorkerThread(threading.Thread): +class WorkerThread(TestThread): # run the entire test in a thread so that the blocking call for # tpc_vote() doesn't hang the test suite. - def __init__(self, storage, trans, method="tpc_finish"): + def __init__(self, testcase, storage, trans, method="tpc_finish"): self.storage = storage self.trans = trans self.method = method - threading.Thread.__init__(self) + TestThread.__init__(self, testcase) - def run(self): + def testrun(self): try: self.storage.tpc_begin(self.trans) oid = self.storage.new_oid() - self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', self.trans) + self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', + self.trans) oid = self.storage.new_oid() - self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', self.trans) + self.storage.store(oid, ZERO, zodb_pickle(MinPO("c")), '', + self.trans) self.storage.tpc_vote(self.trans) if self.method == "tpc_finish": self.storage.tpc_finish(self.trans) else: self.storage.tpc_abort(self.trans) - except Disconnected: + except Disconnected, err: pass class CommitLockTests: @@ -94,7 +97,6 @@ def _cleanup(self): for store, trans in self._storages: - store.tpc_abort(trans) store.close() self._storages = [] @@ -104,6 +106,7 @@ # Start on transaction normally. t = Transaction() + oid = self._storage.new_oid() self._storage.tpc_begin(t) # Start a second transaction on a different connection without @@ -119,7 +122,6 @@ else: self._storages.append((storage2, t2)) - oid = self._storage.new_oid() self._storage.store(oid, ZERO, zodb_pickle(MinPO(1)), '', t) self._storage.tpc_vote(t) if method_name == "tpc_finish": @@ -148,13 +150,13 @@ def _dosetup2(self, storage, trans, tid): self._threads = [] - t = WorkerThread(storage, trans) + t = WorkerThread(self, storage, trans) self._threads.append(t) t.start() def _dowork2(self, method_name): for t in self._threads: - t.join() + t.cleanup() def _duplicate_client(self): "Open another ClientStorage to the same server." From jeremy at zope.com Fri Aug 9 16:31:45 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - TestThread.py:1.2 CommitLockTests.py:1.5 Message-ID: <200208092031.g79KVjX13159@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv13142 Modified Files: CommitLockTests.py Added Files: TestThread.py Log Message: Add TestThread class that helps manage threads started by a unittest. Use TestThread as base class for WorkerThread in CommitLockTests. === StandaloneZODB/ZEO/tests/TestThread.py 1.1 => 1.2 === --- /dev/null Fri Aug 9 16:31:45 2002 +++ StandaloneZODB/ZEO/tests/TestThread.py Fri Aug 9 16:31:45 2002 @@ -0,0 +1,43 @@ +############################################################################## +# +# Copyright (c) 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE +# +############################################################################## +"""A Thread base class for use with unittest.""" + +from cStringIO import StringIO +import threading +import traceback + +class TestThread(threading.Thread): + __super_init = threading.Thread.__init__ + __super_run = threading.Thread.run + + def __init__(self, testcase, group=None, target=None, name=None, + args=(), kwargs={}, verbose=None): + self.__super_init(group, target, name, args, kwargs, verbose) + self.setDaemon(1) + self._testcase = testcase + + def run(self): + try: + self.testrun() + except Exception, err: + s = StringIO() + traceback.print_exc(file=s) + self._testcase.fail("Exception in thread %s:\n%s\n" % + (self, s.getvalue())) + + def cleanup(self, timeout=15): + self.join(timeout) + if self.isAlive(): + self._testcase.fail("Thread did not finish: %s" % self) + === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.4 => 1.5 === --- StandaloneZODB/ZEO/tests/CommitLockTests.py:1.4 Mon Aug 5 18:32:54 2002 +++ StandaloneZODB/ZEO/tests/CommitLockTests.py Fri Aug 9 16:31:45 2002 @@ -13,13 +13,12 @@ ############################################################################## """Tests of the distributed commit lock.""" -import threading - from ZODB.Transaction import Transaction from ZODB.tests.StorageTestBase import zodb_pickle, MinPO import ZEO.ClientStorage from ZEO.Exceptions import Disconnected +from ZEO.tests.TestThread import TestThread ZERO = '\0'*8 @@ -27,19 +26,18 @@ def invalidate(self, *args): pass -class WorkerThread(threading.Thread): +class WorkerThread(TestThread): # run the entire test in a thread so that the blocking call for # tpc_vote() doesn't hang the test suite. - def __init__(self, storage, trans, method="tpc_finish"): + def __init__(self, testcase, storage, trans, method="tpc_finish"): self.storage = storage self.trans = trans self.method = method - threading.Thread.__init__(self) - self.setDaemon(1) + TestThread.__init__(self, testcase) - def run(self): + def testrun(self): try: self.storage.tpc_begin(self.trans) oid = self.storage.new_oid() @@ -151,15 +149,13 @@ def _dosetup2(self, storage, trans, tid): self._threads = [] - t = WorkerThread(storage, trans) + t = WorkerThread(self, storage, trans) self._threads.append(t) t.start() def _dowork2(self, method_name): for t in self._threads: - t.join(10) - for t in self._threads: - self.failIf(t.isAlive()) + t.cleanup() def _duplicate_client(self): "Open another ClientStorage to the same server." From jeremy at zope.com Fri Aug 9 16:32:50 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.41 Message-ID: <200208092032.g79KWop13284@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv13263 Modified Files: StorageServer.py Log Message: Add a close() method to the ZEOStorage that closes connection to client. XXX If select() raises an exception inside asyncore, close the connection. === StandaloneZODB/ZEO/StorageServer.py 1.40 => 1.41 === --- StandaloneZODB/ZEO/StorageServer.py:1.40 Tue Aug 6 19:11:08 2002 +++ StandaloneZODB/ZEO/StorageServer.py Fri Aug 9 16:32:49 2002 @@ -118,11 +118,16 @@ def __init__(self, server): self.server = server self.client = None + self._conn = None # the connection associated with client self.__storage = None self.__storage_id = "uninitialized" self._transaction = None + def close(self): + self._conn.close() + def notifyConnected(self, conn): + self._conn = conn self.client = ClientStub.ClientStorage(conn) def __repr__(self): From jeremy at zope.com Fri Aug 9 16:32:50 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.7 Message-ID: <200208092032.g79KWo613292@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv13263/zrpc Modified Files: connection.py Log Message: Add a close() method to the ZEOStorage that closes connection to client. XXX If select() raises an exception inside asyncore, close the connection. === StandaloneZODB/ZEO/zrpc/connection.py 1.6 => 1.7 === --- StandaloneZODB/ZEO/zrpc/connection.py:1.6 Tue Aug 6 19:10:31 2002 +++ StandaloneZODB/ZEO/zrpc/connection.py Fri Aug 9 16:32:49 2002 @@ -325,7 +325,12 @@ # Do loop only if lock is already acquired. XXX But can't # we already guarantee that the lock is already acquired? while not self.__reply_lock.acquire(0): - asyncore.poll(10.0, self._map) + try: + asyncore.poll(10.0, self._map) + except select.error, err: + log("Closing. asyncore.poll() raised %s." % err, + level=zLOG.BLATHER) + self.close() if self.closed: raise DisconnectedError() self.__reply_lock.release() From jeremy at zope.com Fri Aug 9 16:35:36 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.8 Message-ID: <200208092035.g79KZag13614@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv13601 Modified Files: connection.py Log Message: Import select to make previous checkin work. === StandaloneZODB/ZEO/zrpc/connection.py 1.7 => 1.8 === --- StandaloneZODB/ZEO/zrpc/connection.py:1.7 Fri Aug 9 16:32:49 2002 +++ StandaloneZODB/ZEO/zrpc/connection.py Fri Aug 9 16:35:36 2002 @@ -12,6 +12,7 @@ # ############################################################################## import asyncore +import select import sys import threading import types From jeremy at zope.com Fri Aug 9 17:11:53 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.42 Message-ID: <200208092111.g79LBra17311@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv17296 Modified Files: StorageServer.py Log Message: Enhance comment of _restart() method. === StandaloneZODB/ZEO/StorageServer.py 1.41 => 1.42 === --- StandaloneZODB/ZEO/StorageServer.py:1.41 Fri Aug 9 16:32:49 2002 +++ StandaloneZODB/ZEO/StorageServer.py Fri Aug 9 17:11:52 2002 @@ -381,7 +381,8 @@ self._log("Blocked transaction restarted.") def _restart(self, zeo_storage, delay): - # call the restart() method on the appropriate server + # Return True if the server restarted. + # call the restart() method on the appropriate server. try: zeo_storage.restart(delay) except: From jeremy at zope.com Mon Aug 12 14:05:23 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - CommitLockTests.py:1.6 Message-ID: <200208121805.g7CI5NS02442@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv2430 Modified Files: CommitLockTests.py Log Message: Use local method _get_timestamp(). === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.5 => 1.6 === --- StandaloneZODB/ZEO/tests/CommitLockTests.py:1.5 Fri Aug 9 16:31:45 2002 +++ StandaloneZODB/ZEO/tests/CommitLockTests.py Mon Aug 12 14:05:23 2002 @@ -13,7 +13,10 @@ ############################################################################## """Tests of the distributed commit lock.""" +import time + from ZODB.Transaction import Transaction +from ZODB.TimeStamp import TimeStamp from ZODB.tests.StorageTestBase import zodb_pickle, MinPO import ZEO.ClientStorage @@ -113,7 +116,7 @@ for i in range(4): storage2 = self._duplicate_client() t2 = Transaction() - tid = `ZEO.ClientStorage.get_timestamp()` # XXX why? + tid = self._get_timestamp() dosetup(storage2, t2, tid) if i == 0: storage2.close() From jeremy at zope.com Mon Aug 12 14:24:14 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - CommitLockTests.py:1.7 Message-ID: <200208121824.g7CIOEP04380@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv4368/tests Modified Files: CommitLockTests.py Log Message: Use an Event to wait for each WorkerThread to begin the commit process. === StandaloneZODB/ZEO/tests/CommitLockTests.py 1.6 => 1.7 === --- StandaloneZODB/ZEO/tests/CommitLockTests.py:1.6 Mon Aug 12 14:05:23 2002 +++ StandaloneZODB/ZEO/tests/CommitLockTests.py Mon Aug 12 14:24:13 2002 @@ -13,6 +13,7 @@ ############################################################################## """Tests of the distributed commit lock.""" +import threading import time from ZODB.Transaction import Transaction @@ -38,6 +39,7 @@ self.storage = storage self.trans = trans self.method = method + self.ready = threading.Event() TestThread.__init__(self, testcase) def testrun(self): @@ -49,6 +51,7 @@ oid = self.storage.new_oid() p = zodb_pickle(MinPO("c")) self.storage.store(oid, ZERO, p, '', self.trans) + self.ready.set() self.storage.tpc_vote(self.trans) if self.method == "tpc_finish": self.storage.tpc_finish(self.trans) @@ -106,6 +109,21 @@ # check the commit lock when a client attemps a transaction, # but fails/exits before finishing the commit. + # The general flow of these tests is to start a transaction by + # calling tpc_begin(). Then begin one or more other + # connections that also want to commit. This causes the + # commit lock code to be exercised. Once the other + # connections are started, the first transaction completes. + # Either by commit or abort, depending on whether method_name + # is "tpc_finish." + + # The tests are parameterized by method_name, dosetup(), and + # dowork(). The dosetup() function is called with a + # connectioned client storage, transaction, and timestamp. + # Any work it does occurs after the first transaction has + # started, but before it finishes. The dowork() function + # executes after the first transaction has completed. + # Start on transaction normally. t = Transaction() self._storage.tpc_begin(t) @@ -155,6 +173,7 @@ t = WorkerThread(self, storage, trans) self._threads.append(t) t.start() + t.ready.wait() def _dowork2(self, method_name): for t in self._threads: From jeremy at zope.com Mon Aug 12 14:27:15 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.43 Message-ID: <200208121827.g7CIRF004707@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv4696 Modified Files: StorageServer.py Log Message: Fix two apparent bugs in logic to handle waiting transactions. tpc_abort() and tpc_finish() should always reset _transaction and strategy attributes before calling _handle_waiting(). XXX Not sure that it actually makes a difference, but the code seems simpler. Only issues the "blocked transaction restarted" method when _restart() returns true. === StandaloneZODB/ZEO/StorageServer.py 1.42 => 1.43 === --- StandaloneZODB/ZEO/StorageServer.py:1.42 Fri Aug 9 17:11:52 2002 +++ StandaloneZODB/ZEO/StorageServer.py Mon Aug 12 14:27:14 2002 @@ -314,17 +314,17 @@ if invalidated: self.server.invalidate(self, self.__storage_id, invalidated, self.get_size_info()) - if not self._handle_waiting(): - self._transaction = None - self.strategy = None + self._transaction = None + self.strategy = None + self._handle_waiting() def tpc_abort(self, id): if not self._check_tid(id): return self.strategy.tpc_abort() - if not self._handle_waiting(): - self._transaction = None - self.strategy = None + self._transaction = None + self.strategy = None + self._handle_waiting() # XXX handle new serialnos @@ -363,7 +363,7 @@ d = Delay() self.__storage._waiting.append((d, self)) self._log("Transaction blocked waiting for storage. " - "%d clients waiting." % len(self.__storage._waiting)) + "Clients waiting: %d." % len(self.__storage._waiting)) return d else: self.restart() @@ -372,13 +372,13 @@ while self.__storage._waiting: delay, zeo_storage = self.__storage._waiting.pop(0) if self._restart(zeo_storage, delay): - break - if self.__storage._waiting: - n = len(self.__storage._waiting) - self._log("Blocked transaction restarted. " - "%d clients waiting." % n) - else: - self._log("Blocked transaction restarted.") + if self.__storage._waiting: + n = len(self.__storage._waiting) + self._log("Blocked transaction restarted. " + "Clients waiting: %d" % n) + else: + self._log("Blocked transaction restarted.") + return def _restart(self, zeo_storage, delay): # Return True if the server restarted. From jeremy at zope.com Mon Aug 12 15:42:41 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.44 Message-ID: <200208121942.g7CJgf612300@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv12190 Modified Files: StorageServer.py Log Message: Make sure current transaction is aborted on close. XXX This makes CommitLockTests pass on Win2k for me. === StandaloneZODB/ZEO/StorageServer.py 1.43 => 1.44 === --- StandaloneZODB/ZEO/StorageServer.py:1.43 Mon Aug 12 14:27:14 2002 +++ StandaloneZODB/ZEO/StorageServer.py Mon Aug 12 15:42:40 2002 @@ -115,6 +115,8 @@ removed = 1 class ZEOStorage: + """Proxy to underlying storage for a single remote client.""" + def __init__(self, server): self.server = server self.client = None @@ -124,6 +126,11 @@ self._transaction = None def close(self): + # When this storage closes, we must ensure that it aborts + # any pending transaction. Not sure if this is the clearest way. + if self._transaction is not None: + self.__storage.tpc_abort(self._transaction) + self._transaction is None self._conn.close() def notifyConnected(self, conn): From jeremy at zope.com Mon Aug 12 16:32:27 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.9 Message-ID: <200208122032.g7CKWRX17634@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv17623 Modified Files: connection.py Log Message: Clear up comment inside _do_async_loop() and assert that lock is not held. === StandaloneZODB/ZEO/zrpc/connection.py 1.8 => 1.9 === --- StandaloneZODB/ZEO/zrpc/connection.py:1.8 Fri Aug 9 16:35:36 2002 +++ StandaloneZODB/ZEO/zrpc/connection.py Mon Aug 12 16:32:27 2002 @@ -323,8 +323,8 @@ self.__reply_lock.acquire() # wait until reply... else: - # Do loop only if lock is already acquired. XXX But can't - # we already guarantee that the lock is already acquired? + # Do loop until asyncore handler unlocks the lock. + assert not self.__reply_lock.acquire(0) while not self.__reply_lock.acquire(0): try: asyncore.poll(10.0, self._map) From jeremy at zope.com Wed Aug 14 12:22:23 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.43 Message-ID: <200208141622.g7EGMNL30635@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv30624 Modified Files: ClientStorage.py Log Message: Add some comments and assertions about expected used of condition variable. === ZODB3/ZEO/ClientStorage.py 1.42 => 1.43 === --- ZODB3/ZEO/ClientStorage.py:1.42 Thu Aug 1 15:15:42 2002 +++ ZODB3/ZEO/ClientStorage.py Wed Aug 14 12:22:23 2002 @@ -12,8 +12,9 @@ # ############################################################################## """Network ZODB storage client + +$Id$ """ -__version__='$Revision$'[11:-2] import cPickle import os @@ -62,6 +63,13 @@ disconnected_stub = DisconnectedServerStub() +import thread + +def check_thread_id(txn): + if txn._id is None: # We can't tell what thread created this + return 1 + return txn._id == thread.get_ident() + class ClientStorage: def __init__(self, addr, storage='1', cache_size=20000000, @@ -113,9 +121,12 @@ self.__name__ = name # A ClientStorage only allows one client to commit at a time. - # A client enters the commit state by finding tpc_tid set to - # None and updating it to the new transaction's id. The - # tpc_tid variable is protected by tpc_cond. + # Mutual exclusion is achieved using tpc_cond(), which + # protects _transaction. A thread that wants to assign to + # self._transaction must acquire tpc_cond() first. + + # Invariant: If self._transaction is not None, then tpc_cond() + # must be acquired. self.tpc_cond = threading.Condition() self._transaction = None @@ -218,14 +229,6 @@ raise exc(self._transaction, trans) return 1 - def _check_tid(self, tid, exc=None): - if self.tpc_tid != tid: - if exc is None: - return 0 - else: - raise exc(self.tpc_tid, tid) - return 1 - def abortVersion(self, src, transaction): if self._is_read_only: raise POSException.ReadOnlyError() @@ -330,6 +333,7 @@ def tpc_abort(self, transaction): if transaction is not self._transaction: return + assert check_thread_id(transaction) try: self._server.tpc_abort(self._serial) self._tbuf.clear() @@ -389,6 +393,7 @@ def tpc_finish(self, transaction, f=None): if transaction is not self._transaction: return + assert check_thread_id(transaction) try: if f is not None: f() From jeremy at zope.com Wed Aug 14 12:55:16 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/tests - testZEO.py:1.27 Message-ID: <200208141655.g7EGtGR01477@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv1466 Modified Files: testZEO.py Log Message: Define removefs() for compatibility with Zope 2.5 &c. === ZODB3/ZEO/tests/testZEO.py 1.26 => 1.27 === --- ZODB3/ZEO/tests/testZEO.py:1.26 Thu Aug 8 14:25:10 2002 +++ ZODB3/ZEO/tests/testZEO.py Wed Aug 14 12:55:15 2002 @@ -29,8 +29,23 @@ import ThreadedAsync, ZEO.trigger from ZODB.FileStorage import FileStorage from ZODB.Transaction import Transaction -from ZODB.tests.StorageTestBase import zodb_pickle, MinPO, removefs +from ZODB.tests.StorageTestBase import zodb_pickle, MinPO import zLOG + +try: + from ZODB.tests.StorageTestBase import removefs +except ImportError: + # for compatibility with Zope 2.5 &c. + def removefs(base): + """Remove all files created by FileStorage with path base.""" + for ext in '', '.old', '.tmp', '.lock', '.index', '.pack': + path = base + ext + try: + os.remove(path) + except os.error, err: + if err[0] != errno.ENOENT: + raise + from ZEO.tests import forker, Cache, CommitLockTests, ThreadTests from ZEO.smac import Disconnected From jeremy at zope.com Wed Aug 14 12:56:42 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/tests - testStart.py:1.6 Message-ID: <200208141656.g7EGugQ01624@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv1613 Modified Files: testStart.py Log Message: Define removefs() for compatibility with Zope 2.5 &c. === ZODB3/ZEO/tests/testStart.py 1.5 => 1.6 === --- ZODB3/ZEO/tests/testStart.py:1.5 Thu Aug 8 14:25:10 2002 +++ ZODB3/ZEO/tests/testStart.py Wed Aug 14 12:56:41 2002 @@ -22,7 +22,21 @@ import ZEO.start from ZEO.ClientStorage import ClientStorage from ZEO.util import Environment -from ZODB.tests.StorageTestBase import removefs + +try: + from ZODB.tests.StorageTestBase import removefs +except ImportError: + # for compatibility with Zope 2.5 &c. + def removefs(base): + """Remove all files created by FileStorage with path base.""" + for ext in '', '.old', '.tmp', '.lock', '.index', '.pack': + path = base + ext + try: + os.remove(path) + except os.error, err: + if err[0] != errno.ENOENT: + raise + class StartTests(unittest.TestCase): From jeremy at zope.com Wed Aug 14 13:00:37 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/tests - testStart.py:1.7 testZEO.py:1.28 Message-ID: <200208141700.g7EH0b002077@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv2064/ZEO/tests Modified Files: testStart.py testZEO.py Log Message: removefs() needs errno === ZODB3/ZEO/tests/testStart.py 1.6 => 1.7 === --- ZODB3/ZEO/tests/testStart.py:1.6 Wed Aug 14 12:56:41 2002 +++ ZODB3/ZEO/tests/testStart.py Wed Aug 14 13:00:36 2002 @@ -27,6 +27,8 @@ from ZODB.tests.StorageTestBase import removefs except ImportError: # for compatibility with Zope 2.5 &c. + import errno + def removefs(base): """Remove all files created by FileStorage with path base.""" for ext in '', '.old', '.tmp', '.lock', '.index', '.pack': === ZODB3/ZEO/tests/testZEO.py 1.27 => 1.28 === --- ZODB3/ZEO/tests/testZEO.py:1.27 Wed Aug 14 12:55:15 2002 +++ ZODB3/ZEO/tests/testZEO.py Wed Aug 14 13:00:36 2002 @@ -36,6 +36,8 @@ from ZODB.tests.StorageTestBase import removefs except ImportError: # for compatibility with Zope 2.5 &c. + import errno + def removefs(base): """Remove all files created by FileStorage with path base.""" for ext in '', '.old', '.tmp', '.lock', '.index', '.pack': From jeremy at zope.com Wed Aug 14 15:46:28 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.44 Message-ID: <200208141946.g7EJkSC20742@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv20731 Modified Files: ClientStorage.py Log Message: Small but important correction to condition variable protocol! After setting self._transaction, release the lock. Then reacquire it before the notify(). The wait() call is sufficient to block the other threads; holding the lock is not necessary. As a result, it doesn't matter if the same thread calls tpc_begin() and tpc_abort() for a given transaction. So remove assertion. === ZODB3/ZEO/ClientStorage.py 1.43 => 1.44 === --- ZODB3/ZEO/ClientStorage.py:1.43 Wed Aug 14 12:22:23 2002 +++ ZODB3/ZEO/ClientStorage.py Wed Aug 14 15:46:28 2002 @@ -63,13 +63,6 @@ disconnected_stub = DisconnectedServerStub() -import thread - -def check_thread_id(txn): - if txn._id is None: # We can't tell what thread created this - return 1 - return txn._id == thread.get_ident() - class ClientStorage: def __init__(self, addr, storage='1', cache_size=20000000, @@ -333,13 +326,13 @@ def tpc_abort(self, transaction): if transaction is not self._transaction: return - assert check_thread_id(transaction) try: self._server.tpc_abort(self._serial) self._tbuf.clear() self._seriald.clear() del self._serials[:] finally: + self.tpc_cond.acquire() self._transaction = None self.tpc_cond.notify() self.tpc_cond.release() @@ -358,6 +351,7 @@ self.tpc_cond.release() return self.tpc_cond.wait() + self.tpc_cond.release() if self._server is None: self.tpc_cond.release() @@ -393,7 +387,6 @@ def tpc_finish(self, transaction, f=None): if transaction is not self._transaction: return - assert check_thread_id(transaction) try: if f is not None: f() @@ -405,6 +398,7 @@ self._update_cache() finally: + self.tpc_cond.acquire() self._transaction = None self.tpc_cond.notify() self.tpc_cond.release() From jeremy at zope.com Wed Aug 14 16:44:29 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.45 Message-ID: <200208142044.g7EKiT631857@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv31846 Modified Files: ClientStorage.py Log Message: Allow read-only client connections to call pack(). Not sure about this judgement call. It is really convenient to be able to pack a ZEO server, even if it is only accepting read-only connections. Is pack() a write operation? At one level: Yes, it modifies the data.fs. But it doesn't modify current objects, so it isn't the same as calling store(). We can revisit this later if it ends up being a problem for someone. === ZODB3/ZEO/ClientStorage.py 1.44 => 1.45 === --- ZODB3/ZEO/ClientStorage.py:1.44 Wed Aug 14 15:46:28 2002 +++ ZODB3/ZEO/ClientStorage.py Wed Aug 14 16:44:28 2002 @@ -290,8 +290,7 @@ return oid def pack(self, t=None, rf=None, wait=0, days=0): - if self._is_read_only: - raise POSException.ReadOnlyError() + # XXX Is it okay that read-only connections allow pack()? # rf argument ignored; server will provide it's own implementation if t is None: t = time.time() From barry at wooz.org Fri Aug 16 14:15:06 2002 From: barry at wooz.org (Barry Warsaw) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientStorage.py:1.46 Message-ID: <200208161815.g7GIF6a09549@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv9535 Modified Files: ClientStorage.py Log Message: tpc_begin(): Added a missing self.tpc_cond.acquire() in the except: clause. === StandaloneZODB/ZEO/ClientStorage.py 1.45 => 1.46 === --- StandaloneZODB/ZEO/ClientStorage.py:1.45 Wed Aug 14 16:44:28 2002 +++ StandaloneZODB/ZEO/ClientStorage.py Fri Aug 16 14:15:04 2002 @@ -375,6 +375,7 @@ # Client may have disconnected during the tpc_begin(). # Then notifyDisconnected() will have released the lock. if self._server is not disconnected_stub: + self.tpc_cond.acquire() self._transaction = None self.tpc_cond.release() raise From barry at wooz.org Fri Aug 16 14:16:07 2002 From: barry at wooz.org (Barry Warsaw) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - util.py:1.2 Message-ID: <200208161816.g7GIG7E09674@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv9663 Modified Files: util.py Log Message: Environment.__init__(): ZEO_SERVER.pid should live in the var directory, so it should be joined to self.var, not the local variable `v'. === StandaloneZODB/ZEO/util.py 1.1 => 1.2 === --- StandaloneZODB/ZEO/util.py:1.1 Thu Aug 1 14:50:28 2002 +++ StandaloneZODB/ZEO/util.py Fri Aug 16 14:16:07 2002 @@ -44,7 +44,7 @@ pid = os.environ.get("ZEO_SERVER_PID") if pid is None: - pid = os.path.join(v, "ZEO_SERVER.pid") + pid = os.path.join(self.var, "ZEO_SERVER.pid") self.zeo_pid = pid self.fs = os.path.join(self.var, "Data.fs") From barry at wooz.org Fri Aug 16 14:18:34 2002 From: barry at wooz.org (Barry Warsaw) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testStart.py:1.8 Message-ID: <200208161818.g7GIIYl09903@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv9892 Modified Files: testStart.py Log Message: setUp(): Fix the calculation of the base path for the Environment constructor. It should use the start file, not the sys.executable. testLogRestart(): Fix a race condition; the child process may not have gotten around to creating the log file by the time the parent tried to open it. Use a dumb for/sleep loop. === StandaloneZODB/ZEO/tests/testStart.py 1.7 => 1.8 === --- StandaloneZODB/ZEO/tests/testStart.py:1.7 Wed Aug 14 13:00:36 2002 +++ StandaloneZODB/ZEO/tests/testStart.py Fri Aug 16 14:18:33 2002 @@ -18,6 +18,7 @@ import tempfile import time import unittest +import errno import ZEO.start from ZEO.ClientStorage import ClientStorage @@ -42,13 +43,13 @@ class StartTests(unittest.TestCase): - cmd = "%s %s" % (sys.executable, ZEO.start.__file__) - if cmd[-1] == "c": - cmd = cmd[:-1] - def setUp(self): + startfile = ZEO.start.__file__ + if startfile[-1] == 'c': + startfile = startfile[:-1] + self.env = Environment(startfile) + self.cmd = '%s %s' % (sys.executable, startfile) self.pids = {} - self.env = Environment(self.cmd) def tearDown(self): try: @@ -158,7 +159,14 @@ try: outp = self.fork("-s", "-p", str(port)) self.connect(port=port) - buf1 = open(logfile1).read() + for i in range(10): + try: + buf1 = open(logfile1).read() + except IOError, e: + if e.errno != errno.ENOENT: raise + time.sleep(1) + else: + break self.assert_(buf1) os.rename(logfile1, logfile2) ppid, pid = self.getpids() From tim.one at comcast.net Fri Aug 16 17:42:50 2002 From: tim.one at comcast.net (Tim Peters) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientStorage.py:1.47 Message-ID: <200208162142.g7GLgol29761@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv29742/ZEO Modified Files: ClientStorage.py Log Message: tpc_begin(): self._transaction wasn't protected by the condvar at all anymore. Tried to fix that. Jeremy, please review the new XXX comments. === StandaloneZODB/ZEO/ClientStorage.py 1.46 => 1.47 === --- StandaloneZODB/ZEO/ClientStorage.py:1.46 Fri Aug 16 14:15:04 2002 +++ StandaloneZODB/ZEO/ClientStorage.py Fri Aug 16 17:42:49 2002 @@ -2,14 +2,14 @@ # # Copyright (c) 2001, 2002 Zope Corporation and Contributors. # All Rights Reserved. -# +# # This software is subject to the provisions of the Zope Public License, # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE -# +# ############################################################################## """Network ZODB storage client @@ -117,7 +117,7 @@ # Mutual exclusion is achieved using tpc_cond(), which # protects _transaction. A thread that wants to assign to # self._transaction must acquire tpc_cond() first. - + # Invariant: If self._transaction is not None, then tpc_cond() # must be acquired. self.tpc_cond = threading.Condition() @@ -339,22 +339,20 @@ def tpc_begin(self, transaction, tid=None, status=' '): self.tpc_cond.acquire() while self._transaction is not None: + # It is allowable for a client to call two tpc_begins in a + # row with the same transaction, and the second of these + # must be ignored. if self._transaction == transaction: - # Our tpc_cond lock is re-entrant. It is allowable for a - # client to call two tpc_begins in a row with the same - # transaction, and the second of these must be ignored. Our - # locking is safe because the acquire() above gives us a - # second lock on tpc_cond, and the following release() brings - # us back to owning just the one tpc_cond lock (acquired - # during the first of two consecutive tpc_begins). self.tpc_cond.release() return self.tpc_cond.wait() - self.tpc_cond.release() if self._server is None: - self.tpc_cond.release() + # XXX Why set _transaction to None? It must be None now, else + # XXX we would have stayed in the while loop. + assert self._transaction is None self._transaction = None + self.tpc_cond.release() raise ClientDisconnected() if tid is None: @@ -363,7 +361,13 @@ else: self._ts = TimeStamp(tid) id = tid + # XXX Can setting _transaction be moved above the "id=" business? + # XXX We want to hold the condvar across as little code as possible, + # XXX to slash the chances for deadlock (among other things); e.g., + # XXX if one of those timestamp routines raised an exception, we'd + # XXX hold the condvar forever. self._transaction = transaction + self.tpc_cond.release() try: r = self._server.tpc_begin(id, @@ -373,10 +377,10 @@ tid, status) except: # Client may have disconnected during the tpc_begin(). - # Then notifyDisconnected() will have released the lock. if self._server is not disconnected_stub: self.tpc_cond.acquire() self._transaction = None + self.tpc_cond.notify() self.tpc_cond.release() raise From tim.one at comcast.net Fri Aug 16 17:58:21 2002 From: tim.one at comcast.net (Tim Peters) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientStorage.py:1.48 Message-ID: <200208162158.g7GLwLN31515@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv31300/ZEO Modified Files: ClientStorage.py Log Message: ClientStorage: _basic_init(): repair tpc_cond comments in light of recent changes. tpc_begin: when self._server is None, do tpc_cond.notify() to let other threads waiting for "_transaction is None" to continue. === StandaloneZODB/ZEO/ClientStorage.py 1.47 => 1.48 === --- StandaloneZODB/ZEO/ClientStorage.py:1.47 Fri Aug 16 17:42:49 2002 +++ StandaloneZODB/ZEO/ClientStorage.py Fri Aug 16 17:58:21 2002 @@ -114,12 +114,12 @@ self.__name__ = name # A ClientStorage only allows one client to commit at a time. - # Mutual exclusion is achieved using tpc_cond(), which + # Mutual exclusion is achieved using tpc_cond, which # protects _transaction. A thread that wants to assign to - # self._transaction must acquire tpc_cond() first. - - # Invariant: If self._transaction is not None, then tpc_cond() - # must be acquired. + # self._transaction must acquire tpc_cond first. A thread + # that decides it's done with a transaction (whether via success + # or failure) must set _transaction to None and do + # tpc_cond.notify() before releasing tpc_cond.. self.tpc_cond = threading.Condition() self._transaction = None @@ -352,6 +352,7 @@ # XXX we would have stayed in the while loop. assert self._transaction is None self._transaction = None + self.tpc_cond.notify() self.tpc_cond.release() raise ClientDisconnected() From jeremy at zope.com Fri Aug 16 18:48:36 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.49 Message-ID: <200208162248.g7GMma303889@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv3878 Modified Files: ClientStorage.py Log Message: Further simplifications of the tpc_cond code in tpc_begin(). Not only can we move the assignment of self._transaction about the timestamp / id initialization, but we can eliminate the test for self._server being None. It will never be None. self._server is the first instance variable initialized by __init__(). It is also assigned to in notifyConnected() and notifyDisconnected(), which do not assign it to None. === ZODB3/ZEO/ClientStorage.py 1.48 => 1.49 === --- ZODB3/ZEO/ClientStorage.py:1.48 Fri Aug 16 17:58:21 2002 +++ ZODB3/ZEO/ClientStorage.py Fri Aug 16 18:48:35 2002 @@ -346,15 +346,8 @@ self.tpc_cond.release() return self.tpc_cond.wait() - - if self._server is None: - # XXX Why set _transaction to None? It must be None now, else - # XXX we would have stayed in the while loop. - assert self._transaction is None - self._transaction = None - self.tpc_cond.notify() - self.tpc_cond.release() - raise ClientDisconnected() + self._transaction = transaction + self.tpc_cond.release() if tid is None: self._ts = get_timestamp(self._ts) @@ -362,13 +355,6 @@ else: self._ts = TimeStamp(tid) id = tid - # XXX Can setting _transaction be moved above the "id=" business? - # XXX We want to hold the condvar across as little code as possible, - # XXX to slash the chances for deadlock (among other things); e.g., - # XXX if one of those timestamp routines raised an exception, we'd - # XXX hold the condvar forever. - self._transaction = transaction - self.tpc_cond.release() try: r = self._server.tpc_begin(id, From jeremy at zope.com Fri Aug 16 18:49:41 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.50 Message-ID: <200208162249.g7GMnfP04011@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv3995 Modified Files: ClientStorage.py Log Message: Move tpc_abort() below tpc_begin(). === ZODB3/ZEO/ClientStorage.py 1.49 => 1.50 === --- ZODB3/ZEO/ClientStorage.py:1.49 Fri Aug 16 18:48:35 2002 +++ ZODB3/ZEO/ClientStorage.py Fri Aug 16 18:49:40 2002 @@ -322,20 +322,6 @@ self._server.vote(self._serial) return self._check_serials() - def tpc_abort(self, transaction): - if transaction is not self._transaction: - return - try: - self._server.tpc_abort(self._serial) - self._tbuf.clear() - self._seriald.clear() - del self._serials[:] - finally: - self.tpc_cond.acquire() - self._transaction = None - self.tpc_cond.notify() - self.tpc_cond.release() - def tpc_begin(self, transaction, tid=None, status=' '): self.tpc_cond.acquire() while self._transaction is not None: @@ -374,6 +360,20 @@ self._serial = id self._seriald.clear() del self._serials[:] + + def tpc_abort(self, transaction): + if transaction is not self._transaction: + return + try: + self._server.tpc_abort(self._serial) + self._tbuf.clear() + self._seriald.clear() + del self._serials[:] + finally: + self.tpc_cond.acquire() + self._transaction = None + self.tpc_cond.notify() + self.tpc_cond.release() def tpc_finish(self, transaction, f=None): if transaction is not self._transaction: From jeremy at zope.com Fri Aug 16 18:55:45 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - ClientStorage.py:1.51 Message-ID: <200208162255.g7GMtji04612@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv4601 Modified Files: ClientStorage.py Log Message: Add end_transaction() method. Use this method to set self._transaction to None and notify another thread. === ZODB3/ZEO/ClientStorage.py 1.50 => 1.51 === --- ZODB3/ZEO/ClientStorage.py:1.50 Fri Aug 16 18:49:40 2002 +++ ZODB3/ZEO/ClientStorage.py Fri Aug 16 18:55:44 2002 @@ -351,16 +351,21 @@ except: # Client may have disconnected during the tpc_begin(). if self._server is not disconnected_stub: - self.tpc_cond.acquire() - self._transaction = None - self.tpc_cond.notify() - self.tpc_cond.release() + self.end_transaction() raise self._serial = id self._seriald.clear() del self._serials[:] + def end_transaction(self): + # the right way to set self._transaction to None + # calls notify() on tpc_cond in case there are waiting threads + self.tpc_cond.acquire() + self._transaction = None + self.tpc_cond.notify() + self.tpc_cond.release() + def tpc_abort(self, transaction): if transaction is not self._transaction: return @@ -370,10 +375,7 @@ self._seriald.clear() del self._serials[:] finally: - self.tpc_cond.acquire() - self._transaction = None - self.tpc_cond.notify() - self.tpc_cond.release() + self.end_transaction() def tpc_finish(self, transaction, f=None): if transaction is not self._transaction: @@ -389,10 +391,7 @@ self._update_cache() finally: - self.tpc_cond.acquire() - self._transaction = None - self.tpc_cond.notify() - self.tpc_cond.release() + self.end_transaction() def _update_cache(self): # Iterate over the objects in the transaction buffer and From jeremy at zope.com Thu Aug 22 14:29:14 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - smac.py:1.19 Message-ID: <200208221829.g7MITEf22028@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv22017 Modified Files: smac.py Log Message: Cleanup implementation of string accumulation in handle_write(). Boost the accumulator limit to 60000. Use "".join() to accumulate multiple strings, since it is not unusual to have more than 2 strings to join together. Add comment explaining why we do this stuff. === ZODB3/ZEO/smac.py 1.18 => 1.19 === --- ZODB3/ZEO/smac.py:1.18 Tue Jul 2 03:29:05 2002 +++ ZODB3/ZEO/smac.py Thu Aug 22 14:29:13 2002 @@ -137,21 +137,40 @@ def handle_write(self): output = self.__output while output: - v = output[0] - while len(output)>1 and len(v)<16384: - del output[0] - v += output[0] + # Accumulate output into a single string so that we avoid + # multiple send() calls, but avoid accumulating too much + # data. If we send a very small string and have more data + # to send, we will likely incur delays caused by the + # unfortunate interaction between the Nagle algorithm and + # delayed acks. If we send a very large string, only a + # portion of it will actually be delivered at a time. + + # We chose 60000 as the socket limit by looking at the + # largest strings that we could pass to send() without + # blocking. + + l = 0 + for i in range(len(output)): + l += len(output[i]) + if l > 60000: + break + + i += 1 + # It is very unlikely that i will be 1. + v = "".join(output[:i]) + del output[:i] + try: - n=self.send(v) + n = self.send(v) except socket.error, err: if err[0] in expected_socket_write_errors: break # we couldn't write anything raise if n < len(v): - output[0] = v[n:] + # XXX It's unfortunate that we end up making many + # slices of a large string. + output.insert(0, v[n:]) break # we can't write any more - else: - del output[0] def handle_close(self): self.close() From jeremy at zope.com Thu Aug 22 15:12:37 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO - trigger.py:NONE Message-ID: <200208221912.g7MJCbV26939@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO In directory cvs.zope.org:/tmp/cvs-serv26924 Removed Files: trigger.py Log Message: There were two copies trigger! The one in ZEO/trigger.py was the good code, but we want it to live in ZEO/zrpc/trigger.py. This checkin makes that change. The key checkin of ZEO/trigger.py had this checkin comment: Fix trigger close/__del__. The close() mechanism for an asyncore file_dispatcher is not safe to call multiple times. It's calling os.close() on a file descriptor (int). Guido observed that if you call close() twice, you could be in trouble: 1) First close() call closes FD 6. 2) Another bit of code opens a new file, getting FD 6. 3) Second close() call closes FD 6. Waah! FD 6 is some other file. The workaround attempt here is to define a close() method on a trigger that only closes the file descriptors the first time. Also, make sure that both file descriptors are closed. The previous version only closed the read-end of the pipe. === Removed File ZODB3/ZEO/trigger.py === From jeremy at zope.com Thu Aug 22 15:12:37 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/zrpc - trigger.py:1.3 Message-ID: <200208221912.g7MJCbZ26944@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv26924/zrpc Modified Files: trigger.py Log Message: There were two copies trigger! The one in ZEO/trigger.py was the good code, but we want it to live in ZEO/zrpc/trigger.py. This checkin makes that change. The key checkin of ZEO/trigger.py had this checkin comment: Fix trigger close/__del__. The close() mechanism for an asyncore file_dispatcher is not safe to call multiple times. It's calling os.close() on a file descriptor (int). Guido observed that if you call close() twice, you could be in trouble: 1) First close() call closes FD 6. 2) Another bit of code opens a new file, getting FD 6. 3) Second close() call closes FD 6. Waah! FD 6 is some other file. The workaround attempt here is to define a close() method on a trigger that only closes the file descriptors the first time. Also, make sure that both file descriptors are closed. The previous version only closed the read-end of the pipe. === ZODB3/ZEO/zrpc/trigger.py 1.2 => 1.3 === --- ZODB3/ZEO/zrpc/trigger.py:1.2 Tue Jun 11 15:22:26 2002 +++ ZODB3/ZEO/zrpc/trigger.py Thu Aug 22 15:12:37 2002 @@ -11,13 +11,11 @@ # FOR A PARTICULAR PURPOSE # ############################################################################## -# This module is a simplified version of the select_trigger module -# from Sam Rushing's Medusa server. - import asyncore import os import socket +import string import thread if os.name == 'posix': @@ -55,16 +53,25 @@ # the main thread is trying to remove some] def __init__ (self): - r, w = os.pipe() + r, w = self._fds = os.pipe() self.trigger = w asyncore.file_dispatcher.__init__ (self, r) self.lock = thread.allocate_lock() self.thunks = [] + self._closed = None + + # Override the asyncore close() method, because it seems that + # it would only close the r file descriptor and not w. The + # constructor calls file_dispactcher.__init__ and passes r, + # which would get stored in a file_wrapper and get closed by + # the default close. But that would leave w open... def close(self): - self.del_channel() - self.socket.close() # the read side of the pipe - os.close(self.trigger) # the write side of the pipe + if self._closed is None: + self._closed = 1 + self.del_channel() + for fd in self._fds: + os.close(fd) def __repr__ (self): return '' % id(self) @@ -79,7 +86,6 @@ pass def pull_trigger (self, thunk=None): - # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: try: self.lock.acquire() @@ -96,14 +102,18 @@ try: thunk() except: - (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() - print 'exception in trigger thunk: (%s:%s %s)' % (t, v, tbinfo) + nil, t, v, tbinfo = asyncore.compact_traceback() + print ('exception in trigger thunk:' + ' (%s:%s %s)' % (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() else: + # XXX Should define a base class that has the common methods and + # then put the platform-specific in a subclass named trigger. + # win32-safe version class trigger (asyncore.dispatcher): @@ -118,65 +128,66 @@ w.setsockopt(socket.IPPROTO_TCP, 1, 1) # tricky: get a pair of connected sockets - host='127.0.0.1' - port=19999 + host = '127.0.0.1' + port = 19999 while 1: try: - self.address=(host, port) + self.address = host, port a.bind(self.address) break except: if port <= 19950: raise 'Bind Error', 'Cannot bind trigger!' - port=port - 1 + port -= 1 - a.listen (1) - w.setblocking (0) + a.listen(1) + w.setblocking(0) try: - w.connect (self.address) + w.connect(self.address) except: pass r, addr = a.accept() a.close() - w.setblocking (1) + w.setblocking(1) self.trigger = w - asyncore.dispatcher.__init__ (self, r) + asyncore.dispatcher.__init__(self, r) self.lock = thread.allocate_lock() self.thunks = [] self._trigger_connected = 0 - def __repr__ (self): + def __repr__(self): return '' % id(self) - def readable (self): + def readable(self): return 1 - def writable (self): + def writable(self): return 0 - def handle_connect (self): + def handle_connect(self): pass - def pull_trigger (self, thunk=None): + def pull_trigger(self, thunk=None): if thunk: try: self.lock.acquire() - self.thunks.append (thunk) + self.thunks.append(thunk) finally: self.lock.release() - self.trigger.send ('x') + self.trigger.send('x') - def handle_read (self): - self.recv (8192) + def handle_read(self): + self.recv(8192) try: self.lock.acquire() for thunk in self.thunks: try: thunk() except: - (file, fun, line), t, v, tbinfo = asyncore.compact_traceback() - print 'exception in trigger thunk: (%s:%s %s)' % (t, v, tbinfo) + nil, t, v, tbinfo = asyncore.compact_traceback() + print ('exception in trigger thunk:' + ' (%s:%s %s)' % (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() From jeremy at zope.com Thu Aug 22 15:14:21 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZODB3/ZEO/tests - testZEO.py:1.29 Message-ID: <200208221914.g7MJELH27179@cvs.baymountain.com> Update of /cvs-repository/ZODB3/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv27168 Modified Files: testZEO.py Log Message: Remove unused imports. === ZODB3/ZEO/tests/testZEO.py 1.28 => 1.29 === --- ZODB3/ZEO/tests/testZEO.py:1.28 Wed Aug 14 13:00:36 2002 +++ ZODB3/ZEO/tests/testZEO.py Thu Aug 22 15:14:21 2002 @@ -26,7 +26,6 @@ import unittest import ZEO.ClientStorage, ZEO.StorageServer -import ThreadedAsync, ZEO.trigger from ZODB.FileStorage import FileStorage from ZODB.Transaction import Transaction from ZODB.tests.StorageTestBase import zodb_pickle, MinPO From jeremy at zope.com Fri Aug 23 10:09:09 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO - CHANGES.txt:1.31 Message-ID: <200208231409.g7NE99g12359@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv12352 Modified Files: CHANGES.txt Log Message: Update the changes list. === ZEO/CHANGES.txt 1.30 => 1.31 === --- ZEO/CHANGES.txt:1.30 Mon Aug 5 15:09:54 2002 +++ ZEO/CHANGES.txt Fri Aug 23 10:09:08 2002 @@ -18,6 +18,20 @@ send. The small string variant ran afoul of the Nagle algorithm and delayed TCP acks. + - Fix bugs in server handling of queued transactions + + Several bugs in 2.0a1 could cause the storage to lock up when + it attempted to restart a transaction that was queued waiting + for an earlier transaction to finish. The locking code in the + two-phase commit methods was revised to properly use the + condition variable protocol. Thanks to Tim Peters for + pointing this out. + + - Avoid locking up server on unexpected client exit + + If a client disconnected unexpectedly in the middle of a two- + phase commit, the server would never release the commit lock. + - Very long log messages avoided. Some of the logging messages at BLATHER and lower were @@ -26,11 +40,28 @@ was a list with thousands of elements. These log messages are now truncated at a reasonable length. + - Fix log rotation + + The SIGHUP behavior was fixed. If the ZEO server receives + a SIGHUP, it will re-initialize its logging code. Thus, + it is possible to rotate the log files and then send a HUP. + - Fixed problem handling signals. The asyncore and zrpc error handlers would trap SystemExit if it was raised by a signal handler. They now ignore it. + - pack() can be called on a read-only connection + + This ends up being very convenient for packing a read-only + server, even though it isn't obvious that pack() is a read- + only operation. + + - pack(wait=1) now waits + + A bug caused pack(wait=1) to return immediately, even though + the pack was still running. + - Fix bug in history(). The history() implementation prevent the client from returning @@ -50,6 +81,12 @@ - Removed debug argument to ClientStorage constructor. It had no effect. + + - Removed ZEO.trigger + + There were two copies of the trigger module in the last + release. The one in ZEO.trigger was removed, because it + is only needed in ZEO.zrpc.trigger. - Added minimal tests of start.py. From jeremy at zope.com Fri Aug 23 10:26:48 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - start.py:1.41 Message-ID: <200208231426.g7NEQm916198@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv16187 Modified Files: start.py Log Message: Fix capitalization in rotate_logs() so that it actually works. === ZEO/ZEO/start.py 1.40 => 1.41 === --- ZEO/ZEO/start.py:1.40 Mon Aug 5 17:44:22 2002 +++ ZEO/ZEO/start.py Fri Aug 23 10:26:47 2002 @@ -305,8 +305,8 @@ return # This will work if the minimal logger is in use, but not if some # other logger is active. - import zLog.MinimalLogger - zLog.MinimalLogger._log.initialize() + import zLOG.MinimalLogger + zLOG.MinimalLogger._log.initialize() def rotate_logs_handler(signum, frame): rotate_logs() From jeremy at zope.com Fri Aug 23 10:31:45 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:22 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO/tests - testStart.py:1.9 Message-ID: <200208231431.g7NEVjn16781@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv16770 Modified Files: testStart.py Log Message: Fix testLogRestart(). Use STUPID_LOG_FILE instead of EVENT_LOG_FILE so that it works with older Zopes. Make sure buf1 is defined even if open() never succeeds. === ZEO/ZEO/tests/testStart.py 1.8 => 1.9 === --- ZEO/ZEO/tests/testStart.py:1.8 Fri Aug 16 14:18:33 2002 +++ ZEO/ZEO/tests/testStart.py Fri Aug 23 10:31:44 2002 @@ -154,16 +154,18 @@ port = 9090 logfile1 = tempfile.mktemp(suffix="log") logfile2 = tempfile.mktemp(suffix="log") - os.environ["EVENT_LOG_FILE"] = logfile1 + os.environ["STUPID_LOG_FILE"] = logfile1 try: outp = self.fork("-s", "-p", str(port)) self.connect(port=port) + buf1 = None for i in range(10): try: buf1 = open(logfile1).read() except IOError, e: - if e.errno != errno.ENOENT: raise + if e.errno != errno.ENOENT: + raise time.sleep(1) else: break