From jeremy at zope.com Wed Apr 3 18:48:02 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - forker.py:1.14.2.2 Message-ID: <200204032348.g33Nm2N12602@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv12568/tests Modified Files: Tag: zeo-1_0-debug-branch forker.py Log Message: Make sure the forker *really* exits. === StandaloneZODB/ZEO/tests/forker.py 1.14.2.1 => 1.14.2.2 === pid = os.fork() if pid == 0: - if PROFILE: - p = profile.Profile() - p.runctx("run_server(storage, addr, rd, wr)", globals(), - locals()) - p.dump_stats("stats.s.%d" % os.getpid()) - else: - run_server(storage, addr, rd, wr) - os._exit(0) + try: + if PROFILE: + p = profile.Profile() + p.runctx("run_server(storage, addr, rd, wr)", globals(), + locals()) + p.dump_stats("stats.s.%d" % os.getpid()) + else: + run_server(storage, addr, rd, wr) + finally: + os._exit(0) else: os.close(rd) return pid, ZEOClientExit(wr) From jeremy at zope.com Wed Apr 3 18:49:57 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.34.2.8 Message-ID: <200204032349.g33Nnv113367@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv13270 Modified Files: Tag: zeo-1_0-debug-branch StorageServer.py Log Message: Log the user and description for the transaction. === StandaloneZODB/ZEO/StorageServer.py 1.34.2.7 => 1.34.2.8 === def tpc_begin(self, id, user, description, ext): if __debug__: - log.blather("tpc_begin(%s) %s" % (U64(id), self.logaddr)) + log.blather("tpc_begin(%s, %s, %s) %s" % (U64(id), `user`, + `description`, + self.logaddr)) t = self._transaction if t is not None: if id == t.id: From jeremy at zope.com Thu Apr 4 16:18:16 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - start.py:1.29.2.3 Message-ID: <200204042118.g34LIGd15638@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv15627/ZEO Modified Files: Tag: zeo-1_0-debug-branch start.py Log Message: If getopt fails, print usage. === StandaloneZODB/ZEO/start.py 1.29.2.2 => 1.29.2.3 === ) - opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') + fs = os.path.join(var, 'Data.fs') - fs=os.path.join(var, 'Data.fs') - - usage="""%s [options] [filename] + usage = """%s [options] [filename] where options are: @@ -120,6 +118,13 @@ if no file name is specified, then %s is used. """ % (me, fs) + + try: + opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') + except getopt.error, err: + print err + print usage + sys.exit(1) port=None debug=detailed=0 From jeremy at zope.com Thu Apr 4 16:19:01 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - trigger.py:1.4.2.1 Message-ID: <200204042119.g34LJ1W16119@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv16101/ZEO Modified Files: Tag: zeo-1_0-debug-branch trigger.py Log Message: Handle EAGAIN from os.read() like EAGAIN/EWOULDBLOCK for a socket. Also remove some of the silly formatting (spaces before parens in calls). === StandaloneZODB/ZEO/trigger.py 1.4 => 1.4.2.1 === # from Sam Rushing's Medusa server. - import asyncore -#import asynchat - +import errno import os import socket import string @@ -26,7 +24,7 @@ if os.name == 'posix': - class trigger (asyncore.file_dispatcher): + class trigger(asyncore.file_dispatcher): "Wake up a call to select() running in the main thread" @@ -58,10 +56,10 @@ # new data onto a channel's outgoing data queue at the same time that # the main thread is trying to remove some] - def __init__ (self): + def __init__(self): r, w = self._fds = os.pipe() self.trigger = w - asyncore.file_dispatcher.__init__ (self, r) + asyncore.file_dispatcher.__init__(self, r) self.lock = thread.allocate_lock() self.thunks = [] @@ -69,30 +67,35 @@ os.close(self._fds[0]) os.close(self._fds[1]) - def __repr__ (self): - return '' % id(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): # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: try: self.lock.acquire() - self.thunks.append (thunk) + self.thunks.append(thunk) finally: self.lock.release() - os.write (self.trigger, 'x') + os.write(self.trigger, 'x') - def handle_read (self): - self.recv (8192) + def handle_read(self): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: @@ -101,7 +104,7 @@ except: nil, t, v, tbinfo = asyncore.compact_traceback() print ('exception in trigger thunk:' - ' (%s:%s %s)' % (t, v, tbinfo)) + '(%s:%s %s)' % (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() @@ -113,13 +116,13 @@ # win32-safe version - class trigger (asyncore.dispatcher): + class trigger(asyncore.dispatcher): address = ('127.9.9.9', 19999) - def __init__ (self): - a = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - w = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + def __init__(self): + a = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + w = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set TCP_NODELAY to true to avoid buffering w.setsockopt(socket.IPPROTO_TCP, 1, 1) @@ -137,45 +140,50 @@ raise 'Bind Error', 'Cannot bind trigger!' port=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): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: From jeremy at zope.com Thu Apr 4 16:26:22 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.34.2.9 Message-ID: <200204042126.g34LQM618523@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv18512/ZEO Modified Files: Tag: zeo-1_0-debug-branch StorageServer.py Log Message: In asyncore land, accept() can return None as well as an address pair. === StandaloneZODB/ZEO/StorageServer.py 1.34.2.8 => 1.34.2.9 === def handle_accept(self): try: - sock, addr = self.accept() - except socket.error: - sys.stderr.write('warning: accept failed\n') + r = self.accept() + if r is None: + return + sock, addr = r + except socket.error, err: + log.warning("accept() failed: %s" % err) else: ZEOConnection(self, sock, addr) From jeremy at zope.com Thu Apr 4 17:01:08 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.28.2.9 start.py:1.24.2.3 trigger.py:1.1.8.5 Message-ID: <200204042201.g34M18A29792@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv29777 Modified Files: Tag: zeo-1_0-branch StorageServer.py start.py trigger.py Log Message: Backport fixes from the zeo-1_0-debug-branch. Summary: - Fix the SIGHUP handler so that it doesn't cause asyncore to bail. Fixes in two places. StorageServer must be prepared for accept() to return None. trigger module most be prepared to catch os.error on os.read(). - Replace sys.stderr.write() with zLOG call when accept() fails. - Add log calls when clients are suspend and resumed on the distributed commit lock. === StandaloneZODB/ZEO/StorageServer.py 1.28.2.8 => 1.28.2.9 === from ZODB.Transaction import Transaction import traceback -from zLOG import LOG, INFO, ERROR, TRACE, BLATHER +from zLOG import LOG, INFO, ERROR, TRACE, BLATHER, PROBLEM from ZODB.referencesf import referencesf from thread import start_new_thread from cStringIO import StringIO @@ -126,9 +126,12 @@ def handle_accept(self): try: - sock, addr = self.accept() - except socket.error: - sys.stderr.write('warning: accept failed\n') + x = self.accept() + if x is None: + return + sock, addr = x + except socket.error, err: + LOG('ZEO Server', PROBLEM, 'accept() failed: %s' % err) else: ZEOConnection(self, sock, addr) @@ -457,11 +460,17 @@ def commitlock_suspend(self, resume, args, onerror): self.__storage._waiting.append((resume, args, onerror)) + LOG('ZEO Server', BLATHER, + "Client tpc_begin() suspended. " + "%d clients queued" % len(self.__storage._waiting)) def commitlock_resume(self): waiting = self.__storage._waiting while waiting: resume, args, onerror = waiting.pop(0) + LOG('ZEO Server', BLATHER, + "Client tpc_begin() resumed. " + "%d clients still queued" % len(self.__storage._waiting)) try: if apply(resume, args): break @@ -515,17 +524,18 @@ self.__invalidated=[] def tpc_begin_sync(self, id, user, description, ext): - if self.__closed: return - t=self._transaction - if t is not None and id == t.id: return - storage=self.__storage + if self.__closed: + return + t = self._transaction + if t is not None and id == t.id: + return + storage = self.__storage if storage._transaction is None: self.try_again_sync(id, user, description, ext) else: self.commitlock_suspend(self.try_again_sync, (id, user, description, ext), self.close) - return _noreturn def try_again_sync(self, id, user, description, ext): @@ -537,6 +547,7 @@ t.description=description storage.tpc_begin(t) self.__invalidated=[] + LOG("ZEO Server", BLATHER, "try_again_sync return None") self.message_output('RN.') return 1 @@ -549,6 +560,8 @@ storage = self.__storage r = storage.tpc_finish(t) + self.commitlock_resume() + self._transaction = None if self.__invalidated: self.__server.invalidate(self, self.__storage_id, @@ -556,7 +569,6 @@ self.get_size_info()) self.__invalidated = [] - self.commitlock_resume() def init_storage(storage): if not hasattr(storage,'tpc_vote'): storage.tpc_vote=lambda *args: None === StandaloneZODB/ZEO/start.py 1.24.2.2 => 1.24.2.3 === ) - opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') - fs=os.path.join(var, 'Data.fs') usage="""%s [options] [filename] @@ -120,6 +118,13 @@ if no file name is specified, then %s is used. """ % (me, fs) + + try: + opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') + except getopt.error, err: + print err + print usage + sys.exit(1) port=None debug=detailed=0 === StandaloneZODB/ZEO/trigger.py 1.1.8.4 => 1.1.8.5 === # from Sam Rushing's Medusa server. - import asyncore -#import asynchat - +import errno import os import socket import string @@ -26,7 +24,7 @@ if os.name == 'posix': - class trigger (asyncore.file_dispatcher): + class trigger(asyncore.file_dispatcher): "Wake up a call to select() running in the main thread" @@ -58,10 +56,10 @@ # new data onto a channel's outgoing data queue at the same time that # the main thread is trying to remove some] - def __init__ (self): + def __init__(self): r, w = self._fds = os.pipe() self.trigger = w - asyncore.file_dispatcher.__init__ (self, r) + asyncore.file_dispatcher.__init__(self, r) self.lock = thread.allocate_lock() self.thunks = [] @@ -69,30 +67,35 @@ os.close(self._fds[0]) os.close(self._fds[1]) - def __repr__ (self): - return '' % id(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): # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: try: self.lock.acquire() - self.thunks.append (thunk) + self.thunks.append(thunk) finally: self.lock.release() - os.write (self.trigger, 'x') + os.write(self.trigger, 'x') - def handle_read (self): - self.recv (8192) + def handle_read(self): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: @@ -101,7 +104,7 @@ except: nil, t, v, tbinfo = asyncore.compact_traceback() print ('exception in trigger thunk:' - ' (%s:%s %s)' % (t, v, tbinfo)) + '(%s:%s %s)' % (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() @@ -113,13 +116,13 @@ # win32-safe version - class trigger (asyncore.dispatcher): + class trigger(asyncore.dispatcher): address = ('127.9.9.9', 19999) - def __init__ (self): - a = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - w = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + def __init__(self): + a = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + w = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set TCP_NODELAY to true to avoid buffering w.setsockopt(socket.IPPROTO_TCP, 1, 1) @@ -137,45 +140,50 @@ raise 'Bind Error', 'Cannot bind trigger!' port=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): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: From jeremy at zope.com Thu Apr 4 17:07:20 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO - CHANGES.txt:1.25.2.7 Message-ID: <200204042207.g34M7Kr31150@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv31143 Modified Files: Tag: zeo-1_0-branch CHANGES.txt Log Message: Add note about rotate logs bug. === ZEO/CHANGES.txt 1.25.2.6 => 1.25.2.7 === robust in the face of disconnects and errors. - Upgrade to license to ZPL 2.0 + - Fixed bugs in the storage server and the trigger module that + caused the server to fail with uncaught exceptions when it + received a signal. The start script installs several signal + handlers, so the server should not fail when those signals are + received. These bugs might have occurred in other + circumstances, too. + + Note: The signal handlers are not particularly useful with the + default zLOG backend (STUPID_LOG_FILE). + + - Upgrade to license to ZPL 2.0 ZEO 1.0 beta 5 From barry at wooz.org Thu Apr 4 17:08:24 2002 From: barry at wooz.org (Barry Warsaw) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testZEO.py:1.23 Message-ID: <200204042208.g34M8Of31645@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv31634 Modified Files: testZEO.py Log Message: _dostore(): Extend the argument list to include optional user and description fields, which are assigned to attributes on the Transaction object. === StandaloneZODB/ZEO/tests/testZEO.py 1.22 => 1.23 === def _dostore(self, oid=None, revid=None, data=None, version=None, - already_pickled=0): + already_pickled=0, user=None, description=None): """Do a complete storage transaction. The defaults are: @@ -88,6 +88,10 @@ version = '' # Begin the transaction t = Transaction() + if user is not None: + t.user = user + if description is not None: + t.description = description self._storage.tpc_begin(t) # Store an object r1 = self._storage.store(oid, revid, data, version, t) From jeremy at zope.com Thu Apr 4 18:09:30 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - testZEO.py:1.24 Message-ID: <200204042309.g34N9US14889@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv14866/tests Modified Files: testZEO.py Log Message: Commit the zeo-1_0-debug-branch to the trunk. I expect this code will become ZEO 1.1. === StandaloneZODB/ZEO/tests/testZEO.py 1.23 => 1.24 === """Try to cause the tests to halt""" self.running = 0 + self._storage.status() self._storage.close() self._server.close() os.waitpid(self._pid, 0) @@ -218,6 +219,7 @@ oid = self._storage.new_oid() self._storage.store(oid, None, '', '', t) self._storage.tpc_vote(t) + self._storage.status() self._storage.tpc_finish(t) for store, trans in self._storages: @@ -237,7 +239,7 @@ def _get_timestamp(self): t = time.time() t = apply(TimeStamp,(time.gmtime(t)[:5]+(t%60,))) - return 't' + return `t` class ZEOFileStorageTests(GenericTests): __super_setUp = GenericTests.setUp From jeremy at zope.com Thu Apr 4 18:09:31 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - logger.py:1.2 ClientStorage.py:1.40 StorageServer.py:1.36 smac.py:1.16 start.py:1.31 trigger.py:1.5 zrpc.py:1.23 Message-ID: <200204042309.g34N9VK14901@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv14866 Modified Files: ClientStorage.py StorageServer.py smac.py start.py trigger.py zrpc.py Added Files: logger.py Log Message: Commit the zeo-1_0-debug-branch to the trunk. I expect this code will become ZEO 1.1. === StandaloneZODB/ZEO/logger.py 1.1 => 1.2 === +from types import StringType +from zLOG import * + +__all__ = ["zLogger", "format_msg"] + +_MAX_MSG_SIZE = 120 + +def format_msg(*args): + accum = [] + total_len = 0 + for arg in args: + if not isinstance(arg, StringType): + arg = str(arg) + accum.append(arg) + total_len = total_len + len(arg) + if total_len >= _MAX_MSG_SIZE: + break + m = string.join(accum) + if len(m) > _MAX_MSG_SIZE: + m = m[:_MAX_MSG_SIZE] + ' ...' + return m + +class zLogger: + + def __init__(self, channel): + self.channel = channel + + def __str__(self): + raise RuntimeError, "don't print me" + + def trace(self, msg): + LOG(self.channel, TRACE, msg) + + def debug(self, msg): + LOG(self.channel, DEBUG, msg) + + def blather(self, msg): + LOG(self.channel, BLATHER, msg) + + def info(self, msg): + LOG(self.channel, INFO, msg) + + def problem(self, msg): + LOG(self.channel, PROBLEM, msg) + + def warning(self, msg): + LOG(self.channel, WARNING, msg) + + def error(self, msg, error=None): + LOG(self.channel, ERROR, msg, error=error) + + def panic(self, msg): + LOG(self.channel, PANIC, msg) === StandaloneZODB/ZEO/ClientStorage.py 1.39 => 1.40 === __version__='$Revision$'[11:-2] -import struct, time, os, socket, string, Sync, zrpc, ClientCache -import tempfile, Invalidator, ExtensionClass, thread -import ThreadedAsync - -now=time.time +import struct, time, os, socket, string +import tempfile, thread from struct import pack, unpack +from types import TupleType + +import Invalidator, ExtensionClass +import ThreadedAsync, Sync, zrpc, ClientCache + from ZODB import POSException, BaseStorage from ZODB.TimeStamp import TimeStamp -from zLOG import LOG, PROBLEM, INFO -try: from ZODB.ConflictResolution import ResolvedSerial -except: ResolvedSerial='rs' +from ZEO.logger import zLogger + +log = zLogger("ZEO Client") -TupleType=type(()) +try: + from ZODB.ConflictResolution import ResolvedSerial +except: + ResolvedSerial='rs' class ClientStorageError(POSException.StorageError): """An error occured in the ZEO Client Storage""" @@ -62,8 +67,12 @@ self._info={'length': 0, 'size': 0, 'name': 'ZEO Client', 'supportsUndo':0, 'supportsVersions': 0, } - - self._call=zrpc.asyncRPC(connection, debug=debug, + + if debug: + debug_log = log + else: + debug_log = None + self._call=zrpc.asyncRPC(connection, debug=debug_log, tmin=min_disconnect_poll, tmax=max_disconnect_poll) @@ -132,7 +141,7 @@ # If we can't connect right away, go ahead and open the cache # and start a separate thread to try and reconnect. - LOG("ClientStorage", PROBLEM, "Failed to connect to storage") + log.problem("Failed to connect to storage") self._cache.open() thread.start_new_thread(self._call.connect,(0,)) @@ -140,7 +149,7 @@ # notifyConnected def notifyConnected(self, s): - LOG("ClientStorage", INFO, "Connected to storage") + log.info("Connected to storage") self._lock_acquire() try: @@ -197,7 +206,7 @@ ### responsible for starting the thread that makes the connection. def notifyDisconnected(self, ignored): - LOG("ClientStorage", PROBLEM, "Disconnected from storage") + log.problem("Disconnected from storage") self._connected=0 self._transaction=None thread.start_new_thread(self._call.connect,(0,)) @@ -233,7 +242,7 @@ def close(self): self._lock_acquire() try: - LOG("ClientStorage", INFO, "close") + log.info("close") self._call.closeIntensionally() try: self._tfile.close() @@ -549,6 +558,9 @@ finally: self._lock_release() def sync(self): self._call.sync() + + def status(self): + self._call.sendMessage('status') def getWakeup(_w=[]): if _w: return _w[0] === StandaloneZODB/ZEO/StorageServer.py 1.35 => 1.36 === import asyncore, socket, string, sys, os -from smac import SizedMessageAsyncConnection -from ZODB import POSException import cPickle from cPickle import Unpickler +from cStringIO import StringIO +from thread import start_new_thread +import time +from types import StringType + +from ZODB import POSException from ZODB.POSException import TransactionError, UndoError, VersionCommitError from ZODB.Transaction import Transaction -import traceback -from zLOG import LOG, INFO, ERROR, TRACE, BLATHER from ZODB.referencesf import referencesf -from thread import start_new_thread -from cStringIO import StringIO +from ZODB.utils import U64 + from ZEO import trigger from ZEO import asyncwrap -from ZEO.smac import Disconnected -from types import StringType - -class StorageServerError(POSException.StorageError): pass - -max_blather=120 -def blather(*args): - accum = [] - total_len = 0 - for arg in args: - if not isinstance(arg, StringType): - arg = str(arg) - accum.append(arg) - total_len = total_len + len(arg) - if total_len >= max_blather: - break - m = string.join(accum) - if len(m) > max_blather: m = m[:max_blather] + ' ...' - LOG('ZEO Server', TRACE, m) +from ZEO.smac import Disconnected, SizedMessageAsyncConnection +from ZEO.logger import zLogger, format_msg +class StorageServerError(POSException.StorageError): + pass # We create a special fast pickler! This allows us # to create slightly more efficient pickles and @@ -56,6 +43,8 @@ pickler.fast=1 # Don't use the memo dump=pickler.dump +log = zLogger("ZEO Server") + class StorageServer(asyncore.dispatcher): def __init__(self, connection, storages): @@ -80,14 +69,14 @@ self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() - LOG('ZEO Server', INFO, 'Listening on %s' % repr(connection)) + log.info('Listening on %s' % repr(connection)) self.bind(connection) self.listen(5) def register_connection(self, connection, storage_id): storage=self.__storages.get(storage_id, None) if storage is None: - LOG('ZEO Server', ERROR, "Unknown storage_id: %s" % storage_id) + log.error("Unknown storage_id: %s" % storage_id) connection.close() return None, None @@ -126,18 +115,29 @@ def handle_accept(self): try: - sock, addr = self.accept() - except socket.error: - sys.stderr.write('warning: accept failed\n') + r = self.accept() + if r is None: + return + sock, addr = r + except socket.error, err: + log.warning("accept() failed: %s" % err) else: ZEOConnection(self, sock, addr) - def log_info(self, message, type='info'): - if type=='error': type=ERROR - else: type=INFO - LOG('ZEO Server', type, message) + def status(self): + """Log status information about connections and storages""" - log=log_info + lines = [] + for storage_id, connections in self.__connections.items(): + s = "Storage %s has %d connections" % (storage_id, + len(connections)) + lines.append(s) + for c in connections: + lines.append("%s readable=%s writeable=%s" % ( + c, c.readable(), c.writable())) + lines.append("\t" + c.stats()) + log.info(string.join(lines, "\n")) + return _noreturn storage_methods={} for n in ( @@ -148,6 +148,7 @@ 'tpc_finish', 'undo', 'undoLog', 'undoInfo', 'versionEmpty', 'versions', 'transactionalUndo', 'vote', 'zeoLoad', 'zeoVerify', 'beginZeoVerify', 'endZeoVerify', + 'status' ): storage_methods[n]=1 storage_method=storage_methods.has_key @@ -159,7 +160,8 @@ raise StorageServerError, ( "Couldn\'t import global module %s" % module) - try: r=getattr(m, name) + try: + r=getattr(m, name) except: raise StorageServerError, ( "Couldn\'t find global %s in module %s" % (name, module)) @@ -177,12 +179,52 @@ def __init__(self, server, sock, addr): self.__server=server + self.status = server.status self.__invalidated=[] self.__closed=None - if __debug__: debug='ZEO Server' - else: debug=0 + if __debug__: + debug = log + else: + debug = None + + if __debug__: + # store some detailed statistics about method calls + self._last_method = None + self._t_begin = None + self._t_end = None + self._ncalls = 0 + SizedMessageAsyncConnection.__init__(self, sock, addr, debug=debug) - LOG('ZEO Server', INFO, 'Connect %s %s' % (id(self), `addr`)) + self.logaddr = repr(addr) # form of addr suitable for logging + log.info('Connect %s %s' % (id(self), self.logaddr)) + + def stats(self): + # This method is called via the status() command. The stats + # are of limited use for the current command, because the + # actual invocation of status() will clobber the previous + # method's statistics. + # + # When there are multiple connections active, a new connection + # can always get detailed statistics about other connections. + if __debug__: + if self._last_method == "status": + return "method=status begin=%s end=... ncalls=%d" % ( + self._t_begin, self._ncalls) + if self._t_end is not None and self._t_begin is not None: + delta = self._t_end - self._t_begin + else: + delta = -1 + return "method=%s begin=%s end=%s delta=%.3f ncalls=%d" % ( + self._last_method, self._t_begin, self._t_end, delta, + self._ncalls) + else: + return "" + + def __repr__(self): + return "' or ' closed>')) def close(self): t=self._transaction @@ -196,19 +238,26 @@ self.__server.unregister_connection(self, self.__storage_id) self.__closed=1 SizedMessageAsyncConnection.close(self) - LOG('ZEO Server', INFO, 'Close %s' % id(self)) + log.info('Close %s' % id(self)) def message_input(self, message, dump=dump, Unpickler=Unpickler, StringIO=StringIO, None=None): if __debug__: - if len(message) > max_blather: - tmp = `message[:max_blather]` + + self._t_begin = time.time() + self._t_end = None + + if len(message) > 120: # XXX need constant from logger + tmp = `message[:120]` else: tmp = `message` - blather('message_input', id(self), tmp) + log.trace("message_input %s" % tmp) if self.__storage is None: + if __debug__: + log.blather("register connection to %s from %s" % (message, + self.logaddr)) # This is the first communication from the client self.__storage, self.__storage_id = ( self.__server.register_connection(self, message)) @@ -226,27 +275,42 @@ name, args = args[0], args[1:] if __debug__: - apply(blather, - ("call", id(self), ":", name,) + args) + self._last_method = name + self._ncalls = self._ncalls + 1 + log.debug("call %s%s from %s" % (name, format_msg(args), + self.logaddr)) if not storage_method(name): + log.warning("Invalid method name: %s" % name) + if __debug__: + self._t_end = time.time() raise 'Invalid Method Name', name if hasattr(self, name): r=apply(getattr(self, name), args) else: r=apply(getattr(self.__storage, name), args) - if r is _noreturn: return - except (UndoError, VersionCommitError): - # These are normal usage errors. No need to leg them + if r is _noreturn: + if __debug__: + log.debug("no return to %s" % self.logaddr) + self._t_end = time.time() + return + except (UndoError, VersionCommitError), err: + if __debug__: + log.debug("return error %s to %s" % (err, self.logaddr)) + self._t_end = time.time() + # These are normal usage errors. No need to log them. self.return_error(sys.exc_info()[0], sys.exc_info()[1]) return except: - LOG('ZEO Server', ERROR, 'error', error=sys.exc_info()) + if __debug__: + self._t_end = time.time() + log.error("error", error=sys.exc_info()) self.return_error(sys.exc_info()[0], sys.exc_info()[1]) return if __debug__: - blather("%s R: %s" % (id(self), `r`)) + log.debug("return %s to %s" % (format_msg(r), self.logaddr)) + self._t_end = time.time() r=dump(r,1) self.message_output('R'+r) @@ -256,7 +320,7 @@ err_value = err_type, err_value if __debug__: - blather("%s E: %s" % (id(self), `err_value`)) + log.trace("%s E: %s" % (id(self), `err_value`)) try: r=dump(err_value, 1) except: @@ -292,6 +356,8 @@ } def zeoLoad(self, oid): + if __debug__: + log.blather("zeoLoad(%s) %s" % (U64(oid), self.logaddr)) storage=self.__storage v=storage.modifiedInVersion(oid) if v: pv, sv = storage.load(oid, v) @@ -308,6 +374,8 @@ def beginZeoVerify(self): + if __debug__: + log.blather("beginZeoVerify() %s" % self.logaddr) self.message_output('bN.') return _noreturn @@ -324,6 +392,8 @@ return _noreturn def endZeoVerify(self): + if __debug__: + log.blather("endZeoVerify() %s" % self.logaddr) self.message_output('eN.') return _noreturn @@ -340,11 +410,11 @@ def _pack(self, t, wait=0): try: - LOG('ZEO Server', BLATHER, 'pack begin') + log.blather('pack begin') self.__storage.pack(t, referencesf) - LOG('ZEO Server', BLATHER, 'pack end') + log.blather('pack end') except: - LOG('ZEO Server', ERROR, + log.error( 'Pack failed for %s' % self.__storage_id, error=sys.exc_info()) if wait: @@ -381,6 +451,9 @@ def storea(self, oid, serial, data, version, id, dump=dump): + if __debug__: + log.blather("storea(%s, [%d], %s) %s" % (U64(oid), len(data), + U64(id), self.logaddr)) try: t=self._transaction if t is None or id != t.id: @@ -396,7 +469,7 @@ # all errors need to be serialized to prevent unexpected # returns, which would screw up the return handling. # IOW, Anything that ends up here is evil enough to be logged. - LOG('ZEO Server', ERROR, 'store error', error=sys.exc_info()) + log.error('store error', error=sys.exc_info()) newserial=sys.exc_info()[1] else: if serial != '\0\0\0\0\0\0\0\0': @@ -420,12 +493,17 @@ return self.__storage.tpc_vote(t) def transactionalUndo(self, trans_id, id): + if __debug__: + log.blather("transactionalUndo(%s, %s) %s" % (trans_id, + U64(id), self.logaddr)) t=self._transaction if t is None or id != t.id: raise POSException.StorageTransactionError(self, id) return self.__storage.transactionalUndo(trans_id, self._transaction) def undo(self, transaction_id): + if __debug__: + log.blather("undo(%s) %s" % (transaction_id, self.logaddr)) oids=self.__storage.undo(transaction_id) if oids: self.__server.invalidate( @@ -457,11 +535,15 @@ def commitlock_suspend(self, resume, args, onerror): self.__storage._waiting.append((resume, args, onerror)) + log.blather("suspend %s. %d queued clients" % (resume.im_self, + len(self.__storage._waiting))) def commitlock_resume(self): waiting = self.__storage._waiting while waiting: resume, args, onerror = waiting.pop(0) + log.blather("resuming queued client %s, %d still queued" % ( + resume.im_self, len(waiting))) try: if apply(resume, args): break @@ -471,12 +553,18 @@ # disconnect will have generated its own log event. onerror() except: - LOG('ZEO Server', ERROR, + log.error( "Unexpected error handling queued tpc_begin()", error=sys.exc_info()) onerror() def tpc_abort(self, id): + if __debug__: + try: + log.blather("tpc_abort(%s) %s" % (U64(id), self.logaddr)) + except: + print repr(id) + raise t = self._transaction if t is None or id != t.id: return @@ -492,6 +580,10 @@ self.message_output('UN.') def tpc_begin(self, id, user, description, ext): + if __debug__: + log.blather("tpc_begin(%s, %s, %s) %s" % (U64(id), `user`, + `description`, + self.logaddr)) t = self._transaction if t is not None: if id == t.id: @@ -505,7 +597,8 @@ if storage._transaction is not None: self.commitlock_suspend(self.unlock, (), self.close) return 1 # Return a flag indicating a lock condition. - + + assert id != 't' self._transaction=t=Transaction() t.id=id t.user=user @@ -542,6 +635,8 @@ return 1 def tpc_finish(self, id, user, description, ext): + if __debug__: + log.blather("tpc_finish(%s) %s" % (U64(id), self.logaddr)) t = self._transaction if id != t.id: return @@ -564,7 +659,7 @@ if __name__=='__main__': import ZODB.FileStorage name, port = sys.argv[1:3] - blather(name, port) + log.trace(format_msg(name, port)) try: port='', int(port) except: === StandaloneZODB/ZEO/smac.py 1.15 => 1.16 === import asyncore, string, struct, zLOG, sys, Acquisition import socket, errno -from zLOG import LOG, TRACE, ERROR, INFO +from logger import zLogger # Use the dictionary to make sure we get the minimum number of errno # entries. We expect that EWOULDBLOCK == EAGAIN on most systems -- @@ -48,10 +48,10 @@ SizedMessageAsyncConnection.inheritedAttribute( '__init__')(self, sock, map) self.addr=addr - if debug is not None: - self._debug=debug - elif not hasattr(self, '_debug'): - self._debug=__debug__ and 'smac' + if debug is None and __debug__: + self._debug = zLogger("smac") + else: + self._debug = debug self.__state=None self.__inp=None self.__inpl=0 @@ -132,23 +132,18 @@ def message_output(self, message, pack=struct.pack, len=len): - if self._debug: - if len(message) > 40: m=message[:40]+' ...' - else: m=message - LOG(self._debug, TRACE, 'message_output %s' % `m`) + if self._debug is not None: + if len(message) > 40: + m = message[:40]+' ...' + else: + m = message + self._debug.trace('message_output %s' % `m`) append=self.__append if append is None: raise Disconnected("This action is temporarily unavailable.

") append(pack(">i",len(message))+message) - - def log_info(self, message, type='info'): - if type=='error': type=ERROR - else: type=INFO - LOG('ZEO', type, message) - - log=log_info def close(self): if self.__append is not None: === StandaloneZODB/ZEO/start.py 1.30 => 1.31 === ) - opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') + fs = os.path.join(var, 'Data.fs') - fs=os.path.join(var, 'Data.fs') - - usage="""%s [options] [filename] + usage = """%s [options] [filename] where options are: @@ -121,6 +119,13 @@ if no file name is specified, then %s is used. """ % (me, fs) + try: + opts, args = getopt.getopt(args, 'p:Ddh:U:sS:u:') + except getopt.error, err: + print err + print usage + sys.exit(1) + port=None debug=detailed=0 host='' @@ -217,15 +222,15 @@ import signal signal.signal(signal.SIGTERM, - lambda sig, frame, s=storages: shutdown(s) - ) + lambda sig, frame, s=storages: shutdown(s)) signal.signal(signal.SIGINT, - lambda sig, frame, s=storages: shutdown(s, 0) - ) - try: signal.signal(signal.SIGHUP, rotate_logs_handler) - except: pass - - except: pass + lambda sig, frame, s=storages: shutdown(s, 0)) + try: + signal.signal(signal.SIGHUP, rotate_logs_handler) + except: + pass + except: + pass items=storages.items() items.sort() @@ -236,13 +241,16 @@ ZEO.StorageServer.StorageServer(unix, storages) - try: ppid, pid = os.getppid(), os.getpid() - except: pass # getpid not supported - else: open(zeo_pid,'w').write("%s %s" % (ppid, pid)) + try: + ppid, pid = os.getppid(), os.getpid() + except: + pass # getpid not supported + else: + open(zeo_pid,'w').write("%s %s" % (ppid, pid)) except: # Log startup exception and tell zdaemon not to restart us. - info=sys.exc_info() + info = sys.exc_info() try: import zLOG zLOG.LOG("z2", zLOG.PANIC, "Startup exception", @@ -280,21 +288,29 @@ # unnecessary, since we now use so_reuseaddr. for ignored in 1,2: for socket in asyncore.socket_map.values(): - try: socket.close() - except: pass + try: + socket.close() + except: + pass for storage in storages.values(): - try: storage.close() - except: pass + try: + storage.close() + except: + pass try: from zLOG import LOG, INFO LOG('ZEO Server', INFO, "Shutting down (%s)" % (die and "shutdown" or "restart") ) - except: pass + except: + pass - if die: sys.exit(0) - else: sys.exit(1) + if die: + sys.exit(0) + else: + sys.exit(1) -if __name__=='__main__': main(sys.argv) +if __name__ == '__main__': + main(sys.argv) === StandaloneZODB/ZEO/trigger.py 1.4 => 1.5 === # from Sam Rushing's Medusa server. - import asyncore -#import asynchat - +import errno import os import socket import string @@ -26,7 +24,7 @@ if os.name == 'posix': - class trigger (asyncore.file_dispatcher): + class trigger(asyncore.file_dispatcher): "Wake up a call to select() running in the main thread" @@ -58,10 +56,10 @@ # new data onto a channel's outgoing data queue at the same time that # the main thread is trying to remove some] - def __init__ (self): + def __init__(self): r, w = self._fds = os.pipe() self.trigger = w - asyncore.file_dispatcher.__init__ (self, r) + asyncore.file_dispatcher.__init__(self, r) self.lock = thread.allocate_lock() self.thunks = [] @@ -69,30 +67,35 @@ os.close(self._fds[0]) os.close(self._fds[1]) - def __repr__ (self): - return '' % id(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): # print 'PULL_TRIGGER: ', len(self.thunks) if thunk: try: self.lock.acquire() - self.thunks.append (thunk) + self.thunks.append(thunk) finally: self.lock.release() - os.write (self.trigger, 'x') + os.write(self.trigger, 'x') - def handle_read (self): - self.recv (8192) + def handle_read(self): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: @@ -101,7 +104,7 @@ except: nil, t, v, tbinfo = asyncore.compact_traceback() print ('exception in trigger thunk:' - ' (%s:%s %s)' % (t, v, tbinfo)) + '(%s:%s %s)' % (t, v, tbinfo)) self.thunks = [] finally: self.lock.release() @@ -113,13 +116,13 @@ # win32-safe version - class trigger (asyncore.dispatcher): + class trigger(asyncore.dispatcher): address = ('127.9.9.9', 19999) - def __init__ (self): - a = socket.socket (socket.AF_INET, socket.SOCK_STREAM) - w = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + def __init__(self): + a = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + w = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # set TCP_NODELAY to true to avoid buffering w.setsockopt(socket.IPPROTO_TCP, 1, 1) @@ -137,45 +140,50 @@ raise 'Bind Error', 'Cannot bind trigger!' port=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): + try: + self.recv(8192) + except os.error, err: + if err[0] == errno.EAGAIN: # resource temporarily unavailable + return + raise try: self.lock.acquire() for thunk in self.thunks: === StandaloneZODB/ZEO/zrpc.py 1.22 => 1.23 === self.__call_lr=l.release - def connect(self, tryonce=1, log_type='client'): + def connect(self, tryonce=1): t=self._tmin connection = self._connection debug=self._debug while self.__closed == 0: - if log_type: LOG(log_type, INFO, - 'Trying to connect to server: %s' % `connection`) + LOG("client", INFO, + 'Trying to connect to server: %s' % `connection`) try: if type(connection) is type(''): s=socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) @@ -75,15 +75,15 @@ s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(connection) except Exception, err: - if debug: - LOG(debug, DEBUG, "Failed to connect to server: %s" % err) + if debug is not None: + debug.blather("Failed to connect to server: %s" % err) if tryonce: return 0 time.sleep(t) t=t*2 if t > self._tmax: t=self._tmax else: - if debug: - LOG(debug, DEBUG, "Connected to server") + if debug is not None: + debug.blather("Connected to server") # Make sure the result lock is set, se we don't # get an old result (e.g. the exception that @@ -199,12 +199,12 @@ self._outOfBand=f def message_input(self, m): - if self._debug: + if self._debug is not None: if len(m) > 60: md = repr(m[:60]) + ' ...' else: md = repr(m) - LOG(self._debug, TRACE, 'message_input %s' % md) + self._debug.trace('message_input %s' % md) c=m[:1] if c in 'RE': From jeremy at zope.com Mon Apr 15 15:28:51 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO - README.txt:1.1.2.1 README:NONE Message-ID: <200204151928.g3FJSpt16975@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv16968 Added Files: Tag: zeo-1_0-branch README.txt Removed Files: Tag: zeo-1_0-branch README Log Message: Rename README to README.txt. === Added File ZEO/README.txt === Zope Enterprise Objects Zope Enterprise Objects (ZEO) extends the Zope Object Database (ZODB) to multiple processes, machines, and locations. It provides scalability, high availability, and distribution for ZODB. For more information, see the ZEO Web page at http://www.zope.org/Products/ZEO/. The ZEO package is contained in the directory named ZEO. If you are using Zope, see docs/ZopeREADME.txt; otherwise, see docs/NonZopeREADME.txt. Requirements ZEO requires Python 1.5.2 and Zope 2.2 or higher. It can also be used with StandaloneZODB. === Removed File ZEO/README === From jeremy at zope.com Mon Apr 15 15:43:32 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO - CHANGES.txt:1.25.2.8 Message-ID: <200204151943.g3FJhWs20763@cvs.baymountain.com> Update of /cvs-repository/ZEO In directory cvs.zope.org:/tmp/cvs-serv20756 Modified Files: Tag: zeo-1_0-branch CHANGES.txt Log Message: Add note that no changes were made between 1.0b6 and 1.0final. === ZEO/CHANGES.txt 1.25.2.7 => 1.25.2.8 === + ZEO 1.0 + + No changes since ZEO 1.0 beta 6 + ZEO 1.0 beta 6 Bugs fixed From jeremy at zope.com Tue Apr 23 17:24:46 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - start.py:1.32 Message-ID: <200204232124.g3NLOkU15497@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv15486 Modified Files: start.py Log Message: Ignore SIGXFSZ so that we get exceptions instead of core dumps when the file limit is exceeded. === StandaloneZODB/ZEO/start.py 1.31 => 1.32 === import signal + try: + signal.signal(signal.SIFXFSZ, signal.SIG_IGN) + except AttributeError: + pass signal.signal(signal.SIGTERM, lambda sig, frame, s=storages: shutdown(s)) signal.signal(signal.SIGINT, From jeremy at zope.com Thu Apr 25 16:05:47 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - __init__.py:1.1.2.2 client.py:1.1.2.15 connection.py:1.1.2.8 error.py:1.1.2.3 log.py:1.1.2.3 marshal.py:1.1.2.3 server.py:1.1.2.3 trigger.py:1.1.2.5 Message-ID: <200204252005.g3PK5lD31530@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv31451/zrpc Modified Files: Tag: Standby-branch __init__.py client.py connection.py error.py log.py marshal.py server.py trigger.py Log Message: Update all files to use ZPL 2.0 === StandaloneZODB/ZEO/zrpc/__init__.py 1.1.2.1 => 1.1.2.2 === +# +# 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 +# +############################################################################## # zrpc is a package with the following modules # error -- exceptions raised by zrpc # marshal -- internal, handles basic protocol issues === StandaloneZODB/ZEO/zrpc/client.py 1.1.2.14 => 1.1.2.15 === +# +# 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 errno import select import socket === StandaloneZODB/ZEO/zrpc/connection.py 1.1.2.7 => 1.1.2.8 === +# +# 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 asyncore import sys import threading === StandaloneZODB/ZEO/zrpc/error.py 1.1.2.2 => 1.1.2.3 === +# +# 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 +# +############################################################################## from ZODB import POSException from ZEO.Exceptions import Disconnected === StandaloneZODB/ZEO/zrpc/log.py 1.1.2.2 => 1.1.2.3 === +# +# 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 types import zLOG === StandaloneZODB/ZEO/zrpc/marshal.py 1.1.2.2 => 1.1.2.3 === +# +# 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 cPickle from cStringIO import StringIO import types === StandaloneZODB/ZEO/zrpc/server.py 1.1.2.2 => 1.1.2.3 === +# +# 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 asyncore import socket import types === StandaloneZODB/ZEO/zrpc/trigger.py 1.1.2.4 => 1.1.2.5 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 +# ############################################################################## - # This module is a simplified version of the select_trigger module # from Sam Rushing's Medusa server. - import asyncore From jeremy at zope.com Thu Apr 25 16:05:47 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - Cache.py:1.4.4.4 __init__.py:1.2.6.1 forker.py:1.10.4.8 multi.py:1.4.4.3 speed.py:1.5.4.3 stress.py:1.2.4.4 testTransactionBuffer.py:1.3.2.3 testZEO.py:1.16.4.14 winserver.py:1.2.6.2 Message-ID: <200204252005.g3PK5lx31532@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv31451/tests Modified Files: Tag: Standby-branch Cache.py __init__.py forker.py multi.py speed.py stress.py testTransactionBuffer.py testZEO.py winserver.py Log Message: Update all files to use ZPL 2.0 === StandaloneZODB/ZEO/tests/Cache.py 1.4.4.3 => 1.4.4.4 === +# +# 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 +# +############################################################################## """Tests of the ZEO cache""" from ZODB.Transaction import Transaction === StandaloneZODB/ZEO/tests/__init__.py 1.2 => 1.2.6.1 === +# +# 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 +# +############################################################################## === StandaloneZODB/ZEO/tests/forker.py 1.10.4.7 => 1.10.4.8 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Library for forking storage server and connecting client storage""" import asyncore === StandaloneZODB/ZEO/tests/multi.py 1.4.4.2 => 1.4.4.3 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 multi-client test of the ZEO storage server""" import ZODB, ZODB.DB, ZODB.FileStorage, ZODB.POSException === StandaloneZODB/ZEO/tests/speed.py 1.5.4.2 => 1.5.4.3 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## usage="""Test speed of a ZODB storage Options: === StandaloneZODB/ZEO/tests/stress.py 1.2.4.3 => 1.2.4.4 === +# +# 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 +# +############################################################################## """A ZEO client-server stress test to look for leaks. The stress test should run in an infinite loop and should involve === StandaloneZODB/ZEO/tests/testTransactionBuffer.py 1.3.2.2 => 1.3.2.3 === +# +# 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 random import unittest === StandaloneZODB/ZEO/tests/testZEO.py 1.16.4.13 => 1.16.4.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 1.1 (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. - +# 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 +# +############################################################################## """Test suite for ZEO based on ZODB.tests""" import asyncore === StandaloneZODB/ZEO/tests/winserver.py 1.2.6.1 => 1.2.6.2 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Helper file used to launch ZEO server for Windows tests""" import asyncore From jeremy at zope.com Thu Apr 25 16:06:16 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientCache.py:1.18.6.6 ClientStorage.py:1.35.6.11 ClientStub.py:1.3.2.4 Exceptions.py:1.3.2.2 ServerStub.py:1.3.2.4 StorageServer.py:1.32.6.10 TransactionBuffer.py:1.3.2.5 __init__.py:1.7.6.2 asyncwrap.py:1.2.4.3 fap.py:1.5.6.3 smac.py:1.11.4.6 start.py:1.26.4.4 trigger.py:1.3.4.4 Message-ID: <200204252006.g3PK6GQ32084@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv31451 Modified Files: Tag: Standby-branch ClientCache.py ClientStorage.py ClientStub.py Exceptions.py ServerStub.py StorageServer.py TransactionBuffer.py __init__.py asyncwrap.py fap.py smac.py start.py trigger.py Log Message: Update all files to use ZPL 2.0 === StandaloneZODB/ZEO/ClientCache.py 1.18.6.5 => 1.18.6.6 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 +# ############################################################################## """Implement a client cache === StandaloneZODB/ZEO/ClientStorage.py 1.35.6.10 => 1.35.6.11 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 """ === StandaloneZODB/ZEO/ClientStub.py 1.3.2.3 => 1.3.2.4 === +# +# 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 +# +############################################################################## """Stub for interface exported by ClientStorage""" class ClientStorage: === StandaloneZODB/ZEO/Exceptions.py 1.3.2.1 => 1.3.2.2 === +# +# 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 +# +############################################################################## """Exceptions for ZEO.""" class Disconnected(Exception): === StandaloneZODB/ZEO/ServerStub.py 1.3.2.3 => 1.3.2.4 === +# +# 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 +# +############################################################################## """Stub for interface exposed by StorageServer""" class StorageServer: === StandaloneZODB/ZEO/StorageServer.py 1.32.6.9 => 1.32.6.10 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 server === StandaloneZODB/ZEO/TransactionBuffer.py 1.3.2.4 => 1.3.2.5 === +# +# 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 +# +############################################################################## """A TransactionBuffer store transaction updates until commit or abort. A transaction may generate enough data that it is not practical to === StandaloneZODB/ZEO/__init__.py 1.7.6.1 => 1.7.6.2 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - - +# 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 fap === StandaloneZODB/ZEO/asyncwrap.py 1.2.4.2 => 1.2.4.3 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 wrapper for asyncore that provides robust exception handling. The poll() and loop() calls exported by asyncore can raise exceptions. === StandaloneZODB/ZEO/fap.py 1.5.6.2 => 1.5.6.3 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - - +# 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 +# +############################################################################## """ZEO depends on recent versions of asyncore and cPickle Try to fix up the imports of these to make these dependencies work, === StandaloneZODB/ZEO/smac.py 1.11.4.5 => 1.11.4.6 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 +# ############################################################################## """Sized message async connections """ === StandaloneZODB/ZEO/start.py 1.26.4.3 => 1.26.4.4 === # -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. -# +# 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 +# ############################################################################## - """Start the server storage. """ === StandaloneZODB/ZEO/trigger.py 1.3.4.3 => 1.3.4.4 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - -# This module is a simplified version of the select_trigger module -# from Sam Rushing's Medusa server. - +# 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 asyncore import os From jeremy at zope.com Thu Apr 25 16:19:56 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO/tests - Cache.py:1.4.4.1.2.1 __init__.py:1.2.8.1 forker.py:1.10.4.4.2.1 multi.py:1.4.4.1.2.1 speed.py:1.5.4.1.2.1 stress.py:1.2.4.2.2.1 testTransactionBuffer.py:1.3.2.1.2.1 testZEO.py:1.16.4.4.2.1 winserver.py:1.2.6.1.2.1 Message-ID: <200204252019.g3PKJuf05460@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv5401/ZEO/tests Modified Files: Tag: ZEO2-branch Cache.py __init__.py forker.py multi.py speed.py stress.py testTransactionBuffer.py testZEO.py winserver.py Log Message: Merge the Standby-branch into the ZEO2-branch. The Standby-branch is history. === ZEO/ZEO/tests/Cache.py 1.4.4.1 => 1.4.4.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Tests of the ZEO cache""" from ZODB.Transaction import Transaction @@ -34,16 +38,17 @@ return # Now start an undo transaction - self._transaction.note('undo1') - self._storage.tpc_begin(self._transaction) + t = Transaction() + t.note('undo1') + self._storage.tpc_begin(t) - oids = self._storage.transactionalUndo(tid, self._transaction) + oids = self._storage.transactionalUndo(tid, t) # Make sure this doesn't load invalid data into the cache self._storage.load(oid, '') - - self._storage.tpc_vote(self._transaction) - self._storage.tpc_finish(self._transaction) + + self._storage.tpc_vote(t) + self._storage.tpc_finish(t) assert len(oids) == 1 assert oids[0] == oid === ZEO/ZEO/tests/__init__.py 1.2 => 1.2.8.1 === +# +# 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 +# +############################################################################## === ZEO/ZEO/tests/forker.py 1.10.4.4 => 1.10.4.4.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Library for forking storage server and connecting client storage""" import asyncore @@ -60,7 +64,7 @@ args = (sys.executable, script, str(port), storage_name) + args d = os.environ.copy() d['PYTHONPATH'] = os.pathsep.join(sys.path) - pid = os.spawnve(os.P_NOWAIT, sys.executable, args, os.environ) + pid = os.spawnve(os.P_NOWAIT, sys.executable, args, d) return ('localhost', port), ('localhost', port + 1), pid else: @@ -97,7 +101,8 @@ except os.error: pass - def start_zeo_server(storage, addr): + def start_zeo_server(storage_name, args, addr): + assert isinstance(args, types.TupleType) rd, wr = os.pipe() pid = os.fork() if pid == 0: @@ -110,7 +115,7 @@ globals(), locals()) p.close() else: - run_server(storage, addr, rd, wr) + run_server(addr, rd, wr, storage_name, args) except: print "Exception in ZEO server process" traceback.print_exc() @@ -119,20 +124,27 @@ os.close(rd) return pid, ZEOClientExit(wr) - def run_server(storage, addr, rd, wr): + def load_storage(name, args): + package = __import__("ZODB." + name) + mod = getattr(package, name) + klass = getattr(mod, name) + return klass(*args) + + def run_server(addr, rd, wr, storage_name, args): # in the child, run the storage server global server os.close(wr) ZEOServerExit(rd) import ZEO.StorageServer, ZEO.zrpc.server + storage = load_storage(storage_name, args) server = ZEO.StorageServer.StorageServer(addr, {'1':storage}) ZEO.zrpc.server.loop() storage.close() if isinstance(addr, types.StringType): os.unlink(addr) - def start_zeo(storage, cache=None, cleanup=None, domain="AF_INET", - storage_id="1", cache_size=20000000): + def start_zeo(storage_name, args, cache=None, cleanup=None, + domain="AF_INET", storage_id="1", cache_size=20000000): """Setup ZEO client-server for storage. Returns a ClientStorage instance and a ZEOClientExit instance. @@ -148,11 +160,10 @@ else: raise ValueError, "bad domain: %s" % domain - pid, exit = start_zeo_server(storage, addr) + pid, exit = start_zeo_server(storage_name, args, addr) s = ZEO.ClientStorage.ClientStorage(addr, storage_id, debug=1, client=cache, cache_size=cache_size, min_disconnect_poll=0.5, wait_for_server_on_startup=1) return s, exit, pid - === ZEO/ZEO/tests/multi.py 1.4.4.1 => 1.4.4.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 multi-client test of the ZEO storage server""" import ZODB, ZODB.DB, ZODB.FileStorage, ZODB.POSException @@ -65,16 +69,18 @@ def start_client(addr, client_func=None): pid = os.fork() if pid == 0: - import ZEO.ClientStorage - if VERBOSE: - print "Client process started:", os.getpid() - cli = ZEO.ClientStorage.ClientStorage(addr, client=CLIENT_CACHE) - if client_func is None: - run(cli) - else: - client_func(cli) - cli.close() - os._exit(0) + try: + import ZEO.ClientStorage + if VERBOSE: + print "Client process started:", os.getpid() + cli = ZEO.ClientStorage.ClientStorage(addr, client=CLIENT_CACHE) + if client_func is None: + run(cli) + else: + client_func(cli) + cli.close() + finally: + os._exit(0) else: return pid === ZEO/ZEO/tests/speed.py 1.5.4.1 => 1.5.4.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## usage="""Test speed of a ZODB storage Options: @@ -37,7 +41,7 @@ -t n Number of concurrent threads to run. """ -import asyncore +import asyncore import sys, os, getopt, string, time ##sys.path.insert(0, os.getcwd()) @@ -77,7 +81,7 @@ for r in 1, 10, 100, 1000: t = time.time() conflicts = 0 - + jar = db.open() while 1: try: @@ -101,7 +105,7 @@ else: break jar.close() - + t = time.time() - t if detailed: if threadno is None: @@ -201,11 +205,11 @@ for v in l: tot = tot + v return tot / len(l) - + ##def compress(s): ## c = zlib.compressobj() ## o = c.compress(s) -## return o + c.flush() +## return o + c.flush() if __name__=='__main__': main(sys.argv[1:]) === ZEO/ZEO/tests/stress.py 1.2.4.2 => 1.2.4.2.2.1 === +# +# 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 +# +############################################################################## """A ZEO client-server stress test to look for leaks. The stress test should run in an infinite loop and should involve @@ -90,7 +103,12 @@ pid = os.fork() if pid != 0: return pid - + try: + _start_child(zaddr) + finally: + os._exit(0) + +def _start_child(zaddr): storage = ClientStorage(zaddr, debug=1, min_disconnect_poll=0.5, wait_for_server_on_startup=1) db = ZODB.DB(storage, pool_size=NUM_CONNECTIONS) @@ -116,8 +134,6 @@ else: c.__count += 1 work(c) - - os._exit(0) if __name__ == "__main__": main() === ZEO/ZEO/tests/testTransactionBuffer.py 1.3.2.1 => 1.3.2.1.2.1 === +# +# 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 random import unittest @@ -46,7 +59,7 @@ # the tbuf add a dummy None to invalidates x = x[:2] self.assertEqual(x, data[i]) - + def checkOrderPreserved(self): tbuf = TransactionBuffer() self.doUpdates(tbuf) @@ -61,4 +74,3 @@ def test_suite(): return unittest.makeSuite(TransBufTests, 'check') - === ZEO/ZEO/tests/testZEO.py 1.16.4.4 => 1.16.4.4.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Test suite for ZEO based on ZODB.tests""" import asyncore @@ -53,83 +57,11 @@ def pack(self, t, f): self.storage.pack(t, f, wait=1) -class ZEOTestBase(StorageTestBase.StorageTestBase): - """Version of the storage test class that supports ZEO. - - For ZEO, we don't always get the serialno/exception for a - particular store as the return value from the store. But we - will get no later than the return value from vote. - """ - - def _dostore(self, oid=None, revid=None, data=None, version=None, - already_pickled=0): - """Do a complete storage transaction. - - The defaults are: - - oid=None, ask the storage for a new oid - - revid=None, use a revid of ZERO - - data=None, pickle up some arbitrary data (the integer 7) - - version=None, use the empty string version - - Returns the object's new revision id. - """ - if oid is None: - oid = self._storage.new_oid() - if revid is None: - revid = ZERO - if data is None: - data = MinPO(7) - if not already_pickled: - data = StorageTestBase.zodb_pickle(data) - if version is None: - version = '' - # Begin the transaction - self._storage.tpc_begin(self._transaction) - # Store an object - r1 = self._storage.store(oid, revid, data, version, - self._transaction) - s1 = self._get_serial(r1) - # Finish the transaction - r2 = self._storage.tpc_vote(self._transaction) - s2 = self._get_serial(r2) - self._storage.tpc_finish(self._transaction) - # s1, s2 can be None or dict - assert not (s1 and s2) - return s1 and s1[oid] or s2 and s2[oid] - - def _get_serial(self, r): - """Return oid -> serialno dict from sequence of ZEO replies.""" - d = {} - if r is None: - return None - if type(r) == types.StringType: - raise RuntimeError, "unexpected ZEO response: no oid" - else: - for oid, serial in r: - if isinstance(serial, Exception): - raise serial - d[oid] = serial - return d - -# Some of the ZEO tests depend on the version of FileStorage available -# for the tests. If we run these tests using Zope 2.3, FileStorage -# doesn't support TransactionalUndo. - -if hasattr(FileStorage, 'supportsTransactionalUndo'): - # XXX Assume that a FileStorage that supports transactional undo - # also supports conflict resolution. - class VersionDependentTests( - TransactionalUndoStorage.TransactionalUndoStorage, - TransactionalUndoVersionStorage.TransactionalUndoVersionStorage, - ConflictResolution.ConflictResolvingStorage, - ConflictResolution.ConflictResolvingTransUndoStorage): - pass -else: - class VersionDependentTests: - pass - -class GenericTests(ZEOTestBase, - VersionDependentTests, +class GenericTests(StorageTestBase.StorageTestBase, + TransactionalUndoStorage.TransactionalUndoStorage, + TransactionalUndoVersionStorage.TransactionalUndoVersionStorage, + ConflictResolution.ConflictResolvingStorage, + ConflictResolution.ConflictResolvingTransUndoStorage, Cache.StorageWithCache, Cache.TransUndoStorageWithCache, BasicStorage.BasicStorage, @@ -148,14 +80,10 @@ returns a specific storage, e.g. FileStorage. """ - __super_setUp = StorageTestBase.StorageTestBase.setUp - __super_tearDown = StorageTestBase.StorageTestBase.tearDown - def setUp(self): - self.__super_setUp() - zLOG.LOG("testZEO", zLOG.BLATHER, "setUp() new test") + zLOG.LOG("testZEO", zLOG.INFO, "setUp() %s" % self.id()) self.running = 1 - client, exit, pid = forker.start_zeo(self.getStorage()) + client, exit, pid = forker.start_zeo(*self.getStorage()) self._pids = [pid] self._servers = [exit] self._storage = PackWaitWrapper(client) @@ -169,7 +97,6 @@ for pid in self._pids: os.waitpid(pid, 0) self.delStorage() - self.__super_tearDown() def checkLargeUpdate(self): obj = MinPO("X" * (10 * 128 * 1024)) @@ -177,7 +104,7 @@ class ZEOFileStorageTests(GenericTests): __super_setUp = GenericTests.setUp - + def setUp(self): self.__fs_base = tempfile.mktemp() self.__super_setUp() @@ -185,7 +112,7 @@ def open(self, read_only=0): # XXX Needed to support ReadOnlyStorage tests. Ought to be a # cleaner way. - + # Is this the only way to get the address? addr = self._storage._rpc_mgr.addr[0][1] self._storage.close() @@ -193,11 +120,12 @@ wait_for_server_on_startup=1) def getStorage(self): - return FileStorage(self.__fs_base, create=1) + self.__fs_base = tempfile.mktemp() + return 'FileStorage', (self.__fs_base, '1') def delStorage(self): # file storage appears to create four files - for ext in '', '.index', '.lock', '.tmp': + for ext in '', '.index', '.lock', '.tmp', '.old': path = self.__fs_base + ext try: os.remove(path) @@ -211,11 +139,8 @@ can't be created in the parent process and passed to the child. All the work has to be done in the server's process. """ - __super_setUp = StorageTestBase.StorageTestBase.setUp - __super_tearDown = StorageTestBase.StorageTestBase.tearDown def setUp(self): - self.__super_setUp() args = self.getStorageInfo() name = args[0] args = args[1:] @@ -234,13 +159,12 @@ # the connection should cause the storage server to die time.sleep(0.5) self.delStorage() - self.__super_tearDown() class WindowsZEOFileStorageTests(WindowsGenericTests): def getStorageInfo(self): self.__fs_base = tempfile.mktemp() - return 'FileStorage', self.__fs_base, '1' + return 'FileStorage', (self.__fs_base, '1') # create=1 def delStorage(self): # file storage appears to create four files @@ -251,13 +175,13 @@ except os.error: pass -class ConnectionTests(ZEOTestBase): +class ConnectionTests(StorageTestBase.StorageTestBase): """Tests that explicitly manage the server process. To test the cache or re-connection, these test cases explicit start and stop a ZEO storage server. """ - + __super_tearDown = StorageTestBase.StorageTestBase.tearDown ports = [] @@ -302,14 +226,14 @@ def checkMultipleServers(self): # XXX crude test at first -- just start two servers and do a # commit at each one. - + self._newAddr() self._storage = self.openClientStorage('test', 100000, wait=1) self._dostore() self.shutdownServer(index=0) self._startServer(index=1) - + # If we can still store after shutting down one of the # servers, we must be reconnecting to the other server. @@ -319,7 +243,7 @@ break except Disconnected: time.sleep(0.5) - + def checkDisconnectionError(self): # Make sure we get a Disconnected when we try to read an @@ -352,7 +276,7 @@ # In this case, only one object fits in a cache file. When the # cache files swap, the first object is effectively uncached. - + self._storage = self.openClientStorage('test', 1000, wait=1) oid1 = self._storage.new_oid() obj1 = MinPO("1" * 500) @@ -380,8 +304,12 @@ oid = self._storage.new_oid() obj = MinPO(12) revid1 = self._dostore(oid, data=obj) + zLOG.LOG("checkReconnection", zLOG.INFO, + "About to shutdown server") self.shutdownServer() self.running = 1 + zLOG.LOG("checkReconnection", zLOG.INFO, + "About to restart server") self._startServer(create=0) oid = self._storage.new_oid() obj = MinPO(12) @@ -391,16 +319,19 @@ break except (Disconnected, select.error, thread.error, socket.error), \ err: + zLOG.LOG("checkReconnection", zLOG.INFO, + "Error after server restart; retrying.", + error=sys.exc_info()) get_transaction().abort() time.sleep(0.1) # XXX how long to sleep # XXX This is a bloody pain. We're placing a heavy burden # on users to catch a plethora of exceptions in order to # write robust code. Need to think about implementing # John Heintz's suggestion to make sure all exceptions - # inherit from POSException. + # inherit from POSException. + zLOG.LOG("checkReconnection", zLOG.INFO, "finished") class UnixConnectionTests(ConnectionTests): - __super_setUp = StorageTestBase.StorageTestBase.setUp def setUp(self): """Start a ZEO server using a Unix domain socket @@ -415,7 +346,6 @@ self._servers = [] self._newAddr() self._startServer() - self.__super_setUp() def _newAddr(self): self.addr.append(self._getAddr()) @@ -424,9 +354,10 @@ return '', self.ports.pop() def _startServer(self, create=1, index=0): - fs = FileStorage("%s.%d" % (self.file, index), create=create) + path = "%s.%d" % (self.file, index) addr = self.addr[index] - pid, server = forker.start_zeo_server(fs, addr) + pid, server = forker.start_zeo_server('FileStorage', + (path, create), addr) self._pids.append(pid) self._servers.append(server) @@ -450,14 +381,12 @@ pass class WindowsConnectionTests(ConnectionTests): - __super_setUp = StorageTestBase.StorageTestBase.setUp # XXX these tests are now out-of-date def setUp(self): self.file = tempfile.mktemp() self._startServer() - self.__super_setUp() def _startServer(self, create=1): if create == 0: @@ -490,7 +419,7 @@ def tearDown(self): self.shutdownServer() - + self._storage.close() def get_methods(klass): l = [klass] @@ -538,7 +467,7 @@ if args: print "Did not expect arguments. Got %s" % args return 0 - + tests = makeTestSuite(name_of_test) runner = unittest.TextTestRunner() runner.run(tests) === ZEO/ZEO/tests/winserver.py 1.2.6.1 => 1.2.6.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 +# +############################################################################## """Helper file used to launch ZEO server for Windows tests""" import asyncore From jeremy at zope.com Thu Apr 25 16:19:56 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO/zrpc - __init__.py:1.1.2.1.2.1 client.py:1.1.2.2.2.1 connection.py:1.1.2.2.2.1 error.py:1.1.2.1.2.1 log.py:1.1.2.2.2.1 marshal.py:1.1.2.1.2.1 server.py:1.1.2.1.2.1 trigger.py:1.1.2.1.2.1 Message-ID: <200204252019.g3PKJuC05463@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv5401/ZEO/zrpc Modified Files: Tag: ZEO2-branch __init__.py client.py connection.py error.py log.py marshal.py server.py trigger.py Log Message: Merge the Standby-branch into the ZEO2-branch. The Standby-branch is history. === ZEO/ZEO/zrpc/__init__.py 1.1.2.1 => 1.1.2.1.2.1 === +# +# 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 +# +############################################################################## # zrpc is a package with the following modules # error -- exceptions raised by zrpc # marshal -- internal, handles basic protocol issues === ZEO/ZEO/zrpc/client.py 1.1.2.2 => 1.1.2.2.2.1 === +# +# 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 errno import select import socket @@ -23,13 +36,13 @@ self.tmax = tmax self.connected = 0 self.connection = None + self.closed = 0 # If _thread is not None, then there is a helper thread # attempting to connect. _thread is protected by _connect_lock. self._thread = None self._connect_lock = threading.Lock() self.trigger = None self.thr_async = 0 - self.closed = 0 ThreadedAsync.register_loop_callback(self.set_async) def __repr__(self): @@ -79,18 +92,45 @@ self._connect_lock.release() if self.connection: self.connection.close() + if self.trigger is not None: + self.trigger.close() def set_async(self, map): - # XXX need each connection started with async==0 to have a callback - self.trigger = trigger() - self.thr_async = 1 # XXX needs to be set on the Connection + # This is the callback registered with ThreadedAsync. The + # callback might be called multiple times, so it shouldn't + # create a trigger every time and should never do anything + # after it's closed. + + # It may be that the only case where it is called multiple + # times is in the test suite, where ThreadedAsync's loop can + # be started in a child process after a fork. Regardless, + # it's good to be defensive. + + # XXX need each connection started with async==0 to have a + # callback + if not self.closed and self.trigger is None: + self.trigger = trigger() + self.thr_async = 1 # XXX needs to be set on the Connection def attempt_connect(self): + """Attempt a connection to the server without blocking too long. + + There isn't a crisp definition for too long. When a + ClientStorage is created, it attempts to connect to the + server. If the server isn't immediately available, it can + operate from the cache. This method will start the background + connection thread and wait a little while to see if it + finishes quickly. + """ + # XXX will a single attempt take too long? self.connect() try: event = self._thread.one_attempt except AttributeError: + # An AttributeError means that (1) _thread is None and (2) + # as a consquence of (1) that the connect thread has + # already exited. pass else: event.wait() @@ -132,77 +172,122 @@ # helper for non-local exit def __init__(self, sock): self.sock = sock - + +# When trying to do a connect on a non-blocking socket, some outcomes +# are expected. Set _CONNECT_IN_PROGRESS to the errno value(s) expected +# when an initial connect can't complete immediately. Set _CONNECT_OK +# to the errno value(s) expected if the connect succeeds *or* if it's +# already connected (our code can attempt redundant connects). +if hasattr(errno, "WSAEWOULDBLOCK"): # Windows + _CONNECT_IN_PROGRESS = (errno.WSAEWOULDBLOCK,) + _CONNECT_OK = (0, errno.WSAEISCONN) +else: # Unix + _CONNECT_IN_PROGRESS = (errno.EINPROGRESS,) + _CONNECT_OK = (0, errno.EISCONN) + class ConnectThread(threading.Thread): + """Thread that tries to connect to server given one or more addresses. + The thread is passed a ConnectionManager and the manager's client + as arguments. It calls notifyConnected() on the client when a + socket connects. If notifyConnected() returns without raising an + exception, the thread is done; it calls connect_done() on the + manager and exits. + + The thread will continue to run, attempting connections, until a + successful notifyConnected() or stop() is called. + """ __super_init = threading.Thread.__init__ - def __init__(self, mgr, client, addr, tmin, tmax): - self.__super_init(name="Connect(%s)" % addr) + # We don't expect clients to call any methods of this Thread other + # than close() and those defined by the Thread API. + + def __init__(self, mgr, client, addrs, tmin, tmax): + self.__super_init(name="Connect(%s)" % addrs) self.mgr = mgr self.client = client - self.addr = addr + self.addrs = addrs self.tmin = tmin self.tmax = tmax self.stopped = 0 self.one_attempt = threading.Event() + # A ConnectThread keeps track of whether it has finished a + # call to attempt_connects(). This allows the + # ConnectionManager to make an attempt to connect right away, + # but not block for too long if the server isn't immediately + # available. def stop(self): self.stopped = 1 + # Every method from run() to the end is used internally by the Thread. + def run(self): delay = self.tmin - while not (self.stopped or self.attempt_connects()): + while not self.stopped: + success = self.attempt_connects() if not self.one_attempt.isSet(): self.one_attempt.set() + if success: + break time.sleep(delay) delay *= 2 if delay > self.tmax: delay = self.tmax log("thread exiting: %s" % self.getName()) - + + def close_sockets(self): + for s in self.sockets.keys(): + s.close() + def attempt_connects(self): - "Return true if any connect attempt succeeds." - sockets = {} + """Try connecting to all self.addrs addresses. + + If at least one succeeds, pick a success arbitrarily, close all other + successes (if any), and return true. If none succeed, return false. + """ + + self.sockets = {} # {open socket: connection address} - log("attempting connection on %d sockets" % len(self.addr)) + log("attempting connection on %d sockets" % len(self.addrs)) try: - for domain, addr in self.addr: + for domain, addr in self.addrs: if __debug__: log("attempt connection to %s" % repr(addr), level=zLOG.DEBUG) - s = socket.socket(domain, socket.SOCK_STREAM) + try: + s = socket.socket(domain, socket.SOCK_STREAM) + except socket.error, err: + log("Failed to create socket with domain=%s: %s" % ( + domain, err), level=zLOG.ERROR) + continue s.setblocking(0) + self.sockets[s] = addr + # connect() raises Connected iff it succeeds # XXX can still block for a while if addr requires DNS - e = self.connect(s, addr) - if e is not None: - sockets[s] = addr + self.connect(s) # next wait until they actually connect - while sockets: + while self.sockets: if self.stopped: - for s in sockets.keys(): - s.close() + self.close_sockets() return 0 try: - r, w, x = select.select([], sockets.keys(), [], 1.0) + r, w, x = select.select([], self.sockets.keys(), [], 1.0) except select.error: continue for s in w: - e = self.connect(s, sockets[s]) - if e is None: - del sockets[s] + # connect() raises Connected iff it succeeds + self.connect(s) except Connected, container: s = container.sock - del sockets[s] - # close all the other sockets - for s in sockets.keys(): - s.close() + del self.sockets[s] # don't close the newly connected socket + self.close_sockets() return 1 return 0 - def connect(self, s, addr): - """Call s.connect_ex(addr) and return true if loop should continue. + def connect(self, s): + """Call s.connect_ex(addr); raise Connected iff connection succeeds. We have to handle several possible return values from connect_ex(). If the socket is connected and the initial ZEO @@ -211,27 +296,42 @@ select() loop in the caller and an exception is a principled way to do the abort. - If the socket sonnects and the initial ZEO setup fails or the - connect_ex() returns an error, we close the socket and ignore it. + If the socket sonnects and the initial ZEO setup + (notifyConnected()) fails or the connect_ex() returns an + error, we close the socket, remove it from self.sockets, and + proceed with the other sockets. If connect_ex() returns EINPROGRESS, we need to try again later. """ - - e = s.connect_ex(addr) - if e == errno.EINPROGRESS: - return 1 - elif e == 0: - c = self.test_connection(s, addr) - log("connected to %s" % repr(addr), level=zLOG.DEBUG) - if c: - raise Connected(s) + addr = self.sockets[s] + try: + e = s.connect_ex(addr) + except socket.error, msg: + log("failed to connect to %s: %s" % (addr, msg), + level=zLOG.ERROR) else: - if __debug__: + if e in _CONNECT_IN_PROGRESS: + return + elif e in _CONNECT_OK: + c = self.test_connection(s, addr) + if c: + log("connected to %s" % repr(addr), level=zLOG.DEBUG) + raise Connected(s) + else: log("error connecting to %s: %s" % (addr, errno.errorcode[e]), level=zLOG.DEBUG) - s.close() + # Any execution that doesn't raise Connected() or return + # because of CONNECT_IN_PROGRESS is an error. Make sure the + # socket is closed and remove it from the dict of pending + # sockets. + s.close() + del self.sockets[s] def test_connection(self, s, addr): + # Establish a connection at the zrpc level and call the + # client's notifyConnected(), giving the zrpc application a + # chance to do app-level check of whether the connection is + # okay. c = ManagedConnection(s, addr, self.client, self.mgr) try: self.client.notifyConnected(c) @@ -239,6 +339,8 @@ log("error connecting to server: %s" % str(addr), level=zLOG.ERROR, error=sys.exc_info()) c.close() + # Closing the ZRPC connection will eventually close the + # socket, somewhere in asyncore. return 0 self.mgr.connect_done(c) return 1 === ZEO/ZEO/zrpc/connection.py 1.1.2.2 => 1.1.2.2.2.1 === +# +# 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 asyncore import sys import threading @@ -137,7 +150,7 @@ if flags & ASYNC: if ret is not None: raise ZRPCError("async method %s returned value %s" % - (name, repr(ret)) + (name, repr(ret))) else: if __debug__: log("%s return %s" % (name, short_repr(ret)), zLOG.DEBUG) @@ -162,7 +175,7 @@ def send_reply(self, msgid, ret): msg = self.marshal.encode(msgid, 0, REPLY, ret) self.message_output(msg) - + def return_error(self, msgid, flags, err_type, err_value): if flags is None: self.log_error("Exception raised during decoding") @@ -234,7 +247,7 @@ # XXX The message won't go out right away in this case. It # will wait for the asyncore loop to get control again. Seems # okay to comment our for now, but need to understand better. -## self._do_async_poll() + self._do_async_poll() # handle IO, possibly in async mode @@ -271,7 +284,7 @@ if self.closed: raise DisconnectedError() self.__reply_lock.release() - + def _do_async_poll(self, wait_for_reply=0): "Invoke asyncore mainloop to get pending message out." @@ -284,13 +297,9 @@ asyncore.poll(0.0, self._map) class ServerConnection(Connection): + """Connection on the server side""" + # XXX Do we need this class anymore? - def _do_async_poll(self, wait=0): - """If this is a server, there is no explicit IO to do""" - pass - - # XXX _do_async_loop is never called. Should it be defined as - # above anyway? class ManagedServerConnection(ServerConnection): """A connection that notifies its ConnectionManager of closing""" @@ -310,7 +319,7 @@ """A connection that notifies its ConnectionManager of closing. A managed connection also defers the ThreadedAsync work to its - manager. + manager. """ __super_init = Connection.__init__ __super_close = Connection.close @@ -324,6 +333,9 @@ # the manager should actually close the trigger del self.trigger + def set_async(self, map): + pass + def _prepare_async(self): # Don't do the register_loop_callback that the superclass does pass @@ -345,4 +357,3 @@ def close(self): self.__super_close() self.__mgr.notify_closed(self) - === ZEO/ZEO/zrpc/error.py 1.1.2.1 => 1.1.2.1.2.1 === +# +# 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 +# +############################################################################## from ZODB import POSException from ZEO.Exceptions import Disconnected @@ -9,4 +22,3 @@ class DisconnectedError(ZRPCError, Disconnected): """The database storage is disconnected from the storage server.""" - === ZEO/ZEO/zrpc/log.py 1.1.2.2 => 1.1.2.2.2.1 === +# +# 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 types import zLOG === ZEO/ZEO/zrpc/marshal.py 1.1.2.1 => 1.1.2.1.2.1 === +# +# 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 cPickle from cStringIO import StringIO import types @@ -7,7 +20,7 @@ # It's okay to share a single Pickler as long as it's in fast # mode, which means that it doesn't have a memo. - + pickler = cPickle.Pickler() pickler.fast = 1 pickle = pickler.dump @@ -46,7 +59,7 @@ r = getattr(m, name) except AttributeError: raise ZRPCError("module %s has no global %s" % (module, name)) - + safe = getattr(r, '__no_side_effects__', 0) if safe: return r === ZEO/ZEO/zrpc/server.py 1.1.2.1 => 1.1.2.1.2.1 === +# +# 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 asyncore import socket import types @@ -14,7 +27,7 @@ reuse_addr = 1 - def __init__(self, addr, factory=Connection, reuse_addr=None): + def __init__(self, addr, factory=Connection, reuse_addr=None): self.__super_init() self.addr = addr self.factory = factory === ZEO/ZEO/zrpc/trigger.py 1.1.2.1 => 1.1.2.1.2.1 === -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. +# +# 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 # ############################################################################## - # This module is a simplified version of the select_trigger module # from Sam Rushing's Medusa server. - import asyncore -#import asynchat import os import socket -import string import thread - + if os.name == 'posix': class trigger (asyncore.file_dispatcher): @@ -136,6 +61,11 @@ self.lock = thread.allocate_lock() self.thunks = [] + 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 + def __repr__ (self): return '' % id(self) @@ -199,7 +129,7 @@ if port <= 19950: raise 'Bind Error', 'Cannot bind trigger!' port=port - 1 - + a.listen (1) w.setblocking (0) try: @@ -250,7 +180,3 @@ self.thunks = [] finally: self.lock.release() - - - - From jeremy at zope.com Thu Apr 25 16:20:25 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO/misc - custom_zodb.py:1.2.2.1.2.1 Message-ID: <200204252020.g3PKKP505580@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO/misc In directory cvs.zope.org:/tmp/cvs-serv5401/ZEO/misc Modified Files: Tag: ZEO2-branch custom_zodb.py Log Message: Merge the Standby-branch into the ZEO2-branch. The Standby-branch is history. === ZEO/ZEO/misc/custom_zodb.py 1.2.2.1 => 1.2.2.1.2.1 === if 0: # Change the 0 to 1 to enable! - + # ZEO Unix Domain Socket # This import isn't strictly necessary but is helpful when @@ -30,4 +30,3 @@ Storage=ZODB.FileStorage.FileStorage( os.path.join(INSTANCE_HOME, 'var', 'Data.fs'), ) - From jeremy at zope.com Thu Apr 25 16:20:25 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: ZEO/ZEO - ClientCache.py:1.18.6.3.2.1 ClientStorage.py:1.35.6.4.2.1 ClientStub.py:1.3.2.2.2.1 Exceptions.py:1.3.2.1.2.1 ServerStub.py:1.3.2.1.2.1 StorageServer.py:1.32.6.3.2.1 TransactionBuffer.py:1.3.2.2.2.1 __init__.py:1.7.6.1.2.1 asyncwrap.py:1.2.4.1.2.1 fap.py:1.5.6.1.2.1 smac.py:1.11.4.4.2.1 start.py:1.26.4.2.2.1 trigger.py:1.3.4.2.2.1 Invalidator.py:NONE zrpc.py:NONE Message-ID: <200204252020.g3PKKPK05589@cvs.baymountain.com> Update of /cvs-repository/ZEO/ZEO In directory cvs.zope.org:/tmp/cvs-serv5401/ZEO Modified Files: Tag: ZEO2-branch ClientCache.py ClientStorage.py ClientStub.py Exceptions.py ServerStub.py StorageServer.py TransactionBuffer.py __init__.py asyncwrap.py fap.py smac.py start.py trigger.py Removed Files: Tag: ZEO2-branch Invalidator.py zrpc.py Log Message: Merge the Standby-branch into the ZEO2-branch. The Standby-branch is history. === ZEO/ZEO/ClientCache.py 1.18.6.3 => 1.18.6.3.2.1 === (432/532 lines abridged) -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." [-=- -=- -=- 432 lines omitted -=- -=- -=-] - if len(vdlen) != 4: break - vdlen=unpack(">i", vdlen)[0] - if vlen+dlen+42+vdlen > tlen: break + vdlen = read(4) + if len(vdlen) != 4: + break + vdlen = unpack(">i", vdlen)[0] + if vlen+dlen+42+vdlen > tlen: + break seek(vdlen, 1) - vs=read(8) - if read(4) != h[9:13]: break - else: vs=None + vs = read(8) + if read(4) != h[9:13]: + break + else: + vs = None if h[8] in 'vn': - if current: index[oid]=-pos - else: index[oid]=pos - serial[oid]=h[-8:], vs + if current: + index[oid] = -pos + else: + index[oid] = pos + serial[oid] = h[-8:], vs else: if serial.has_key(oid): # We have a record for this oid, but it was invalidated! del serial[oid] del index[oid] - - - pos=pos+tlen + + + pos = pos + tlen f.seek(pos) - try: f.truncate() - except: pass - + try: + f.truncate() + except: + pass + return pos === ZEO/ZEO/ClientStorage.py 1.35.6.4 => 1.35.6.4.2.1 === -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. +# +# 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 @@ -192,7 +121,7 @@ # Prevent multiple new_oid calls from going out. The _oids # variable should only be modified while holding the - # oid_cond. + # oid_cond. self.oid_cond = threading.Condition() commit_lock = threading.Lock() @@ -204,10 +133,12 @@ self._oid='\0\0\0\0\0\0\0\0' def close(self): - self._rpc_mgr.close() + if self._tbuf is not None: + self._tbuf.close() if self._cache is not None: self._cache.close() - + self._rpc_mgr.close() + def registerDB(self, db, limit): """Register that the storage is controlled by the given DB.""" log2(INFO, "registerDB(%s, %s)" % (repr(db), repr(limit))) @@ -220,7 +151,7 @@ return 1 def notifyConnected(self, c): - log2(INFO, "Connected to storage") + log2(INFO, "Connected to storage via %s" % repr(c)) stub = ServerStub.StorageServer(c) self._oids = [] @@ -228,6 +159,7 @@ # XXX Why is this synchronous? If it were async, verification # would start faster. stub.register(str(self._storage), self._is_read_only) + self._info.update(stub.get_info()) self.verify_cache(stub) # Don't make the server available to clients until after @@ -263,10 +195,10 @@ def getSize(self): return self._info['size'] - + def supportsUndo(self): return self._info['supportsUndo'] - + def supportsVersions(self): return self._info['supportsVersions'] @@ -286,7 +218,7 @@ else: raise exc(self._transaction, trans) return 1 - + def _check_tid(self, tid, exc=None): if self.tpc_tid != tid: if exc is None: @@ -305,11 +237,6 @@ self._tbuf.invalidate(oid, src) return oids - def close(self): - self._rpc_mgr.close() - if self._cache is not None: - self._cache.close() - def commitVersion(self, src, dest, transaction): if self._is_read_only: raise POSException.ReadOnlyError() @@ -327,10 +254,10 @@ return oids def history(self, oid, version, length=1): - return self._server.history(oid, version, length) - + return self._server.history(oid, version, length) + def loadSerial(self, oid, serial): - return self._server.loadSerial(oid, serial) + return self._server.loadSerial(oid, serial) def load(self, oid, version, _stuff=None): p = self._cache.load(oid, version) @@ -347,7 +274,7 @@ if s: return p, s raise KeyError, oid # no non-version data for this - + def modifiedInVersion(self, oid): v = self._cache.modifiedInVersion(oid) if v is not None: @@ -366,7 +293,7 @@ oid = self._oids.pop() self.oid_cond.release() return oid - + def pack(self, t=None, rf=None, wait=0, days=0): if self._is_read_only: raise POSException.ReadOnlyError() @@ -391,7 +318,7 @@ if self._is_read_only: raise POSException.ReadOnlyError() self._check_trans(transaction, POSException.StorageTransactionError) - self._server.storea(oid, serial, data, version, self._serial) + self._server.storea(oid, serial, data, version, self._serial) self._tbuf.store(oid, version, data) return self._check_serials() @@ -400,7 +327,7 @@ return self._server.vote(self._serial) return self._check_serials() - + def tpc_abort(self, transaction): if transaction is not self._transaction: return @@ -412,7 +339,7 @@ self.tpc_cond.notify() self.tpc_cond.release() - def tpc_begin(self, transaction): + def tpc_begin(self, transaction, tid=None, status=' '): self.tpc_cond.acquire() while self._transaction is not None: if self._transaction == transaction: @@ -423,7 +350,7 @@ if self._server is None: self.tpc_cond.release() raise ClientDisconnected() - + self._ts = get_timestamp(self._ts) id = `self._ts` self._transaction = transaction @@ -432,7 +359,8 @@ r = self._server.tpc_begin(id, transaction.user, transaction.description, - transaction._extension) + transaction._extension, + tid, status) except: # Client may have disconnected during the tpc_begin(). # Then notifyDisconnected() will have released the lock. @@ -463,7 +391,7 @@ def _update_cache(self): # Iterate over the objects in the transaction buffer and - # update or invalidate the cache. + # update or invalidate the cache. self._cache.checkSize(self._tbuf.get_size()) self._tbuf.begin_iterate() while 1: @@ -476,7 +404,7 @@ if t is None: break oid, v, p = t - if p is None: # an invalidation + if p is None: # an invalidation s = None else: s = self._seriald[oid] @@ -501,7 +429,7 @@ # XXX what are the sync issues here? oids = self._server.undo(transaction_id) for oid in oids: - self._cache.invalidate(oid, '') + self._cache.invalidate(oid, '') return oids def undoInfo(self, first=0, last=-20, specification=None): @@ -510,7 +438,7 @@ def undoLog(self, first, last, filter=None): if filter is not None: return () # can't pass a filter to server - + return self._server.undoLog(first, last) # Eek! def versionEmpty(self, version): @@ -528,7 +456,7 @@ self._info.update(dict) def begin(self): - self._tfile = tempfile.TemporaryFile() + self._tfile = tempfile.TemporaryFile(suffix=".inv") self._pickler = cPickle.Pickler(self._tfile, 1) self._pickler.fast = 1 # Don't use the memo @@ -544,6 +472,7 @@ self._pickler.dump((0,0)) self._tfile.seek(0) unpick = cPickle.Unpickler(self._tfile) + f = self._tfile self._tfile = None while 1: @@ -552,6 +481,7 @@ break self._cache.invalidate(oid, version=version) self._db.invalidate(oid, version=version) + f.close() def Invalidate(self, args): for oid, version in args: === ZEO/ZEO/ClientStub.py 1.3.2.2 => 1.3.2.2.2.1 === +# +# 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 +# +############################################################################## """Stub for interface exported by ClientStorage""" class ClientStorage: def __init__(self, rpc): self.rpc = rpc - + def beginVerify(self): self.rpc.callAsync('begin') === ZEO/ZEO/Exceptions.py 1.3.2.1 => 1.3.2.1.2.1 === +# +# 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 +# +############################################################################## """Exceptions for ZEO.""" class Disconnected(Exception): === ZEO/ZEO/ServerStub.py 1.3.2.1 => 1.3.2.1.2.1 === +# +# 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 +# +############################################################################## """Stub for interface exposed by StorageServer""" class StorageServer: @@ -28,7 +41,7 @@ return self.rpc.call('new_oids') else: return self.rpc.call('new_oids', n) - + def pack(self, t, wait=None): if wait is None: self.rpc.call('pack', t) @@ -41,8 +54,8 @@ def storea(self, oid, serial, data, version, id): self.rpc.callAsync('storea', oid, serial, data, version, id) - def tpc_begin(self, id, user, descr, ext): - return self.rpc.call('tpc_begin', id, user, descr, ext) + def tpc_begin(self, id, user, descr, ext, tid, status): + return self.rpc.call('tpc_begin', id, user, descr, ext, tid, status) def vote(self, trans_id): return self.rpc.call('vote', trans_id) @@ -58,7 +71,7 @@ def commitVersion(self, src, dest, id): return self.rpc.call('commitVersion', src, dest, id) - + def history(self, oid, version, length=None): if length is not None: return self.rpc.call('history', oid, version) @@ -104,5 +117,3 @@ return self.rpc.call('versions') else: return self.rpc.call('versions', max) - - === ZEO/ZEO/StorageServer.py 1.32.6.3 => 1.32.6.3.2.1 === -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. # -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. +# 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 server @@ -135,7 +64,7 @@ c = ManagedServerConnection(sock, addr, ZEOStorage(self), self) log("new connection %s: %s" % (addr, `c`)) return c - + def register(self, storage_id, proxy): """Register a connection's use with a particular storage. @@ -150,7 +79,7 @@ l.append(proxy) def invalidate(self, conn, storage_id, invalidated=(), info=0): - for p in self.connections[storage_id]: + for p in self.connections.get(storage_id, ()): if invalidated and p is not conn: p.client.Invalidate(invalidated) else: @@ -188,7 +117,7 @@ def notifyConnected(self, conn): self.client = ClientStub.ClientStorage(conn) - + def __repr__(self): tid = self._transaction and repr(self._transaction.id) if self.__storage: @@ -196,8 +125,8 @@ repr(self.__storage._transaction.id) else: stid = None - return "" % (id(self), tid, - stid) + name = self.__class__.__name__ + return "<%s %X trans=%s s_trans=%s>" % (name, id(self), tid, stid) def _log(self, msg, level=zLOG.INFO, error=None, pid=os.getpid()): zLOG.LOG("ZEO Server:%s:%s" % (pid, self.__storage_id), @@ -303,11 +232,11 @@ t.start() def _pack(self, t, wait=0): - try: + try: self.__storage.pack(t, referencesf) except: - self._log('ZEO Server', zLOG.ERROR, - 'Pack failed for %s' % self.__storage_id, + self._log('Pack failed for %s' % self.__storage_id, + zLOG.ERROR, error=sys.exc_info()) if wait: raise @@ -379,8 +308,11 @@ def transactionalUndo(self, trans_id, id): self._check_tid(id, exc=StorageTransactionError) - return self.__storage.transactionalUndo(trans_id, self._transaction) - + oids = self.__storage.transactionalUndo(trans_id, self._transaction) + for oid in oids: + self.__invalidated.append((oid, None)) + return oids + def undo(self, transaction_id): oids = self.__storage.undo(transaction_id) if oids: @@ -401,7 +333,7 @@ # be the same.) The new transaction's proxy sets its _transaction # and continues from there. - def tpc_begin(self, id, user, description, ext): + def tpc_begin(self, id, user, description, ext, tid, status): if self._transaction is not None: if self._transaction.id == id: self._log("duplicate tpc_begin(%s)" % repr(id)) @@ -418,11 +350,11 @@ if self.__storage._transaction is not None: d = Delay() - self.__storage.__waiting.append((d, self, t)) + self.__storage.__waiting.append((d, self, t, tid, status)) return d self._transaction = t - self.__storage.tpc_begin(t) + self.__storage.tpc_begin(t, tid, status) self.__invalidated = [] def tpc_finish(self, id): @@ -451,20 +383,20 @@ self._transaction = None self.__invalidated = [] - def _restart_delayed_transaction(self, delay, trans): + def _restart_delayed_transaction(self, delay, trans, tid, status): self._transaction = trans - self.__storage.tpc_begin(trans) + self.__storage.tpc_begin(trans, tid, status) self.__invalidated = [] assert self._transaction.id == self.__storage._transaction.id delay.reply(None) def _handle_waiting(self): if self.__storage.__waiting: - delay, proxy, trans = self.__storage.__waiting.pop(0) - proxy._restart_delayed_transaction(delay, trans) + delay, proxy, trans, tid, status = self.__storage.__waiting.pop(0) + proxy._restart_delayed_transaction(delay, trans, tid, status) if self is proxy: return 1 - + def new_oids(self, n=100): """Return a sequence of n new oids, where n defaults to 100""" if n < 0: === ZEO/ZEO/TransactionBuffer.py 1.3.2.2 => 1.3.2.2.2.1 === +# +# 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 +# +############################################################################## """A TransactionBuffer store transaction updates until commit or abort. A transaction may generate enough data that it is not practical to @@ -12,9 +25,9 @@ import cPickle class TransactionBuffer: - + def __init__(self): - self.file = tempfile.TemporaryFile() + self.file = tempfile.TemporaryFile(suffix=".tbuf") self.count = 0 self.size = 0 # It's safe to use a fast pickler because the only objects @@ -22,6 +35,9 @@ self.pickler = cPickle.Pickler(self.file, 1) self.pickler.fast = 1 + def close(self): + self.file.close() + def store(self, oid, version, data): """Store oid, version, data for later retrieval""" self.pickler.dump((oid, version, data)) @@ -59,8 +75,8 @@ oid_ver_data = self.unpickler.load() self.count -= 1 return oid_ver_data - + def get_size(self): """Return size of data stored in buffer (just a hint).""" - + return self.size === ZEO/ZEO/__init__.py 1.7.6.1 => 1.7.6.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - - +# 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 fap === ZEO/ZEO/asyncwrap.py 1.2.4.1 => 1.2.4.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - +# 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 wrapper for asyncore that provides robust exception handling. The poll() and loop() calls exported by asyncore can raise exceptions. @@ -40,7 +44,7 @@ raise else: break - + def poll(*args, **kwargs): try: apply(asyncore.poll, args, kwargs) === ZEO/ZEO/fap.py 1.5.6.1 => 1.5.6.1.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - - +# 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 +# +############################################################################## """ZEO depends on recent versions of asyncore and cPickle Try to fix up the imports of these to make these dependencies work, @@ -21,7 +24,7 @@ try: m=imp.find_module('ZServer', [where]) except: return 0 else: return 1 - + def fap(): # if we are using an old version of Python, our asyncore is likely to @@ -33,12 +36,12 @@ except: # Try a little harder to import ZServer import os, imp - + location = package_home() location = os.path.split(location)[0] location = os.path.split(location)[0] location = os.path.split(location)[0] - + if whiff(location): sys.path.append(location) try: === ZEO/ZEO/smac.py 1.11.4.4 => 1.11.4.4.2.1 === -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. +# +# 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 # ############################################################################## """Sized message async connections @@ -198,7 +127,7 @@ def readable(self): return 1 - + def writable(self): if len(self.__output) == 0: return 0 === ZEO/ZEO/start.py 1.26.4.2 => 1.26.4.2.2.1 === -# -# Zope Public License (ZPL) Version 1.0 -# ------------------------------------- -# -# Copyright (c) Digital Creations. All rights reserved. -# -# This license has been certified as Open Source(tm). -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions in source code must retain the above copyright -# notice, this list of conditions, and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions, and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Digital Creations requests that attribution be given to Zope -# in any manner possible. Zope includes a "Powered by Zope" -# button that is installed by default. While it is not a license -# violation to remove this button, it is requested that the -# attribution remain. A significant investment has been put -# into Zope, and this effort will continue if the Zope community -# continues to grow. This is one way to assure that growth. -# -# 4. All advertising materials and documentation mentioning -# features derived from or use of this software must display -# the following acknowledgement: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# In the event that the product being advertised includes an -# intact Zope distribution (with copyright and license included) -# then this clause is waived. -# -# 5. Names associated with Zope or Digital Creations must not be used to -# endorse or promote products derived from this software without -# prior written permission from Digital Creations. -# -# 6. Modified redistributions of any form whatsoever must retain -# the following acknowledgment: -# -# "This product includes software developed by Digital Creations -# for use in the Z Object Publishing Environment -# (http://www.zope.org/)." -# -# Intact (re-)distributions of any official Zope release do not -# require an external acknowledgement. -# -# 7. Modifications are encouraged but must be packaged separately as -# patches to official Zope releases. Distributions that do not -# clearly separate the patches from the original work must be clearly -# labeled as unofficial distributions. Modifications which do not -# carry the name Zope may be packaged in any form, as long as they -# conform to all of the clauses above. -# -# -# Disclaimer -# -# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY -# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. -# -# -# This software consists of contributions made by Digital Creations and -# many individuals on behalf of Digital Creations. Specific -# attributions are listed in the accompanying credits file. +# +# 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 # ############################################################################## - """Start the server storage. """ @@ -99,7 +27,7 @@ d=os.path.split(d)[0] if not d or d=='.': d=os.getcwd() n=n-1 - + return d def get_storage(m, n, cache={}): @@ -150,7 +78,7 @@ -D -- Run in debug mode -U -- Unix-domain socket file to listen on - + -u username or uid number The username to run the ZEO server as. You may want to run @@ -191,7 +119,7 @@ print usage print msg sys.exit(1) - + port=None debug=0 host='' @@ -234,7 +162,7 @@ from zLOG import LOG, INFO, ERROR # Try to set uid to "-u" -provided uid. - # Try to set gid to "-u" user's primary group. + # Try to set gid to "-u" user's primary group. # This will only work if this script is run by root. try: import pwd @@ -249,7 +177,7 @@ uid = pwd.getpwuid(UID)[2] gid = pwd.getpwuid(UID)[3] else: - raise KeyError + raise KeyError try: if gid is not None: try: @@ -355,7 +283,7 @@ "Shutting down (%s)" % (die and "shutdown" or "restart") ) except: pass - + if die: sys.exit(0) else: sys.exit(1) === ZEO/ZEO/trigger.py 1.3.4.2 => 1.3.4.2.2.1 === +############################################################################## # +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. +# All Rights Reserved. +# # This software is subject to the provisions of the Zope Public License, -# Version 1.1 (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. - -# This module is a simplified version of the select_trigger module -# from Sam Rushing's Medusa server. - +# 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 asyncore import os import socket import string import thread - + if os.name == 'posix': class trigger (asyncore.file_dispatcher): @@ -138,7 +139,7 @@ if port <= 19950: raise 'Bind Error', 'Cannot bind trigger!' port=port - 1 - + a.listen (1) w.setblocking (0) try: === Removed File ZEO/ZEO/Invalidator.py === === Removed File ZEO/ZEO/zrpc.py === From jeremy at zope.com Thu Apr 25 17:04:15 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - start.py:1.26.4.2.2.2 Message-ID: <200204252104.g3PL4FB16917@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv16906 Modified Files: Tag: ZEO2-branch start.py Log Message: Merge a bunch of changes from ZEO 1.0. Do a better job of computing INSTANCE_HOME and choosing var directory. Add -d option (set STUPID_LOG_SEVERITY). Cleanly log and report fatal errors that occur during startup. Recover from failures to set signal handlers. (try/finally should have been try/except.) Do not require platform to support getppd() or getpid(). Remove prof option. === StandaloneZODB/ZEO/start.py 1.26.4.2.2.1 => 1.26.4.2.2.2 === last=a - INSTANCE_HOME=os.environ.get('INSTANCE_HOME', directory(me, 4)) + 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(INSTANCE_HOME, 'var', 'ZEO_SERVER.pid') + os.path.join(var, 'ZEO_SERVER.pid') ) - fs=os.path.join(INSTANCE_HOME, 'var', 'Data.fs') + fs = os.path.join(var, 'Data.fs') usage="""%s [options] [filename] @@ -77,6 +87,8 @@ -D -- Run in debug mode + -d -- Set STUPD_LOG_SEVERITY to -300 + -U -- Unix-domain socket file to listen on -u username or uid number @@ -114,36 +126,41 @@ """ % (me, fs) try: - opts, args = getopt.getopt(args, 'p:Dh:U:sS:u:P:') + opts, args = getopt.getopt(args, 'p:Dh:U:sS:u:P:d') except getopt.error, msg: print usage print msg sys.exit(1) - port=None - debug=0 - host='' - unix=None - Z=1 - UID='nobody' + port = None + debug = 0 + host = '' + unix =None + Z = 1 + UID = 'nobody' prof = None + detailed = 0 for o, v in opts: - if o=='-p': port=string.atoi(v) - elif o=='-h': host=v - elif o=='-U': unix=v - elif o=='-u': UID=v - elif o=='-D': debug=1 - elif o=='-s': Z=0 - elif o=='-P': prof = v + if o=='-p': + port = int(v) + elif o=='-h': + host = v + elif o=='-U': + unix = v + elif o=='-u': + UID = v + elif o=='-D': + debug = 1 + elif o=='-d': + detailed = 1 + elif o=='-s': + Z = 0 + elif o=='-P': + prof = v if prof: Z = 0 - try: - from ZServer.medusa import asyncore - sys.modules['asyncore']=asyncore - except: pass - if port is None and unix is None: print usage print 'No port specified.' @@ -157,7 +174,10 @@ fs=args[0] __builtins__.__debug__=debug - if debug: os.environ['Z_DEBUG_MODE']='1' + if debug: + os.environ['Z_DEBUG_MODE'] = '1' + if detailed: + os.environ['STUPID_LOG_SEVERITY'] = '-300' from zLOG import LOG, INFO, ERROR @@ -199,54 +219,77 @@ import zdaemon zdaemon.run(sys.argv, '') - storages={} - for o, v in opts: - if o=='-S': - n, m = string.split(v,'=') - if string.find(m,':'): - # we got an attribute name - m, a = string.split(m,':') - else: - # attribute name must be same as storage name - a=n - storages[n]=get_storage(m,a) - - if not storages: - import ZODB.FileStorage - storages['1']=ZODB.FileStorage.FileStorage(fs) - - # Try to set up a signal handler try: - import signal - signal.signal(signal.SIGTERM, - lambda sig, frame, s=storages: shutdown(s) - ) - signal.signal(signal.SIGINT, - lambda sig, frame, s=storages: shutdown(s, 0) - ) - signal.signal(signal.SIGHUP, rotate_logs_handler) - - finally: pass - - items=storages.items() - items.sort() - for kv in items: - LOG('ZEO Server', INFO, 'Serving %s:\t%s' % kv) + import ZEO.StorageServer, asyncore + + storages={} + for o, v in opts: + if o=='-S': + n, m = string.split(v,'=') + if string.find(m,':'): + # we got an attribute name + m, a = string.split(m,':') + else: + # attribute name must be same as storage name + a=n + storages[n]=get_storage(m,a) + + if not storages: + import ZODB.FileStorage + storages['1']=ZODB.FileStorage.FileStorage(fs) - if not unix: unix=host, port + # Try to set up a signal handler + try: + import signal + + try: + signal.signal(signal.SIFXFSZ, signal.SIG_IGN) + except AttributeError: + pass + signal.signal(signal.SIGTERM, + lambda sig, frame, s=storages: shutdown(s)) + signal.signal(signal.SIGINT, + lambda sig, frame, s=storages: shutdown(s, 0)) + try: + signal.signal(signal.SIGHUP, rotate_logs_handler) + except: + pass + except: + pass + + items=storages.items() + items.sort() + for kv in items: + LOG('ZEO Server', INFO, 'Serving %s:\t%s' % kv) + + if not unix: unix=host, port - if prof: - cmds = \ - "StorageServer.StorageServer(unix, storages);" \ - 'open(zeo_pid,"w").write("%s %s" % (os.getppid(), os.getpid()));' \ - "asyncore.loop()" - import profile - profile.run(cmds, prof) - else: StorageServer.StorageServer(unix, storages) - open(zeo_pid,'w').write("%s %s" % (os.getppid(), os.getpid())) - asyncore.loop() + + try: + ppid, pid = os.getppid(), os.getpid() + except: + pass # getpid not supported + else: + open(zeo_pid,'w').write("%s %s" % (ppid, pid)) + + except: + # Log startup exception and tell zdaemon not to restart us. + info = sys.exc_info() + try: + import zLOG + zLOG.LOG("z2", zLOG.PANIC, "Startup exception", + error=info) + except: + pass + + import traceback + apply(traceback.print_exception, info) + + sys.exit(0) + + asyncore.loop() def rotate_logs(): import zLOG From jeremy at zope.com Fri Apr 26 15:25:30 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/tests - forker.py:1.10.4.4.2.2 stress.py:1.2.4.2.2.2 testZEO.py:1.16.4.4.2.2 Message-ID: <200204261925.g3QJPU211404@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/tests In directory cvs.zope.org:/tmp/cvs-serv11377/tests Modified Files: Tag: ZEO2-branch forker.py stress.py testZEO.py Log Message: First step words protocol negotiation. New client sends a 4-byte protocol id to the server. XXX Is this sufficient for now? Also, rename "wait_for_server_on_startup" to "wait". This change affects a ctor calls in a bunch of files. === StandaloneZODB/ZEO/tests/forker.py 1.10.4.4.2.1 => 1.10.4.4.2.2 === cache_size=cache_size, min_disconnect_poll=0.5, - wait_for_server_on_startup=1) + wait=1) return s, exit, pid === StandaloneZODB/ZEO/tests/stress.py 1.2.4.2.2.1 => 1.2.4.2.2.2 === def _start_child(zaddr): - storage = ClientStorage(zaddr, debug=1, min_disconnect_poll=0.5, - wait_for_server_on_startup=1) + storage = ClientStorage(zaddr, debug=1, min_disconnect_poll=0.5, wait=1) db = ZODB.DB(storage, pool_size=NUM_CONNECTIONS) setup(db.open()) conns = [] === StandaloneZODB/ZEO/tests/testZEO.py 1.16.4.4.2.1 => 1.16.4.4.2.2 === import ThreadedAsync, ZEO.trigger from ZODB.FileStorage import FileStorage +from ZODB.Transaction import Transaction import thread import zLOG @@ -102,6 +103,63 @@ obj = MinPO("X" * (10 * 128 * 1024)) self._dostore(data=obj) + def checkCommitLockOnCommit(self): + self._checkCommitLock("tpc_finish") + + def checkCommitLockOnAbort(self): + self._checkCommitLock("tpc_abort") + + def _checkCommitLock(self, method_name): + # check the commit lock when a client attemps a transaction, + # but fails/exits before finishing the commit. + + # Start on transaction normally. + t = Transaction() + self._storage.tpc_begin(t) + + # Start a second transaction on a different connection without + # blocking the test thread. + self._storages = [] + for i in range(3): + storage2 = self._duplicate_client() + t2 = Transaction() + tid = ZEO.ClientStorage.get_timestamp() + storage2._server.tpc_begin(tid, t2.user, t2.description, + t2._extension, None, ' ') + if i == 0: + storage2.close() + else: + self._storages.append((storage2, t2)) + + oid = self._storage.new_oid() + self._storage.store(oid, None, '', '', t) + self._storage.tpc_vote(t) + self._storage.status() + self._storage.tpc_finish(t) + + for store, trans in self._storages: + store.tpc_abort(trans) + store.close() + + # Make sure the server is still responsive + self._dostore() + + def _duplicate_client(self): + "Open another ClientStorage to the same server." + # XXX argh it's hard to find the actual address + # The rpc mgr addr attribute is a list. Each element in the + # list is a socket domain (AF_INET, AF_UNIX, etc.) and an + # address. + addr = self._storage._rpc_mgr.addr[0][1] + new = ZEO.ClientStorage.ClientStorage(addr, wait=1) + new.registerDB(DummyDB(), None) + return new + + def _get_timestamp(self): + t = time.time() + t = apply(TimeStamp,(time.gmtime(t)[:5]+(t%60,))) + return `t` + class ZEOFileStorageTests(GenericTests): __super_setUp = GenericTests.setUp @@ -117,7 +175,7 @@ addr = self._storage._rpc_mgr.addr[0][1] self._storage.close() self._storage = ZEO.ClientStorage.ClientStorage(addr, read_only=1, - wait_for_server_on_startup=1) + wait=1) def getStorage(self): self.__fs_base = tempfile.mktemp() @@ -365,7 +423,7 @@ base = ZEO.ClientStorage.ClientStorage(self.addr, client=cache, cache_size=cache_size, - wait_for_server_on_startup=wait, + wait=wait, min_disconnect_poll=0.1) storage = PackWaitWrapper(base) storage.registerDB(DummyDB(), None) @@ -403,8 +461,7 @@ base = ZEO.ClientStorage.ClientStorage(self.addr, client=cache, cache_size=cache_size, - debug=1, - wait_for_server_on_startup=wait) + debug=1, wait=1) storage = PackWaitWrapper(base) storage.registerDB(DummyDB(), None) return storage From jeremy at zope.com Fri Apr 26 15:25:30 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.1.2.2.2.2 marshal.py:1.1.2.1.2.2 Message-ID: <200204261925.g3QJPUd11409@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv11377/zrpc Modified Files: Tag: ZEO2-branch connection.py marshal.py Log Message: First step words protocol negotiation. New client sends a 4-byte protocol id to the server. XXX Is this sufficient for now? Also, rename "wait_for_server_on_startup" to "wait". This change affects a ctor calls in a bunch of files. === StandaloneZODB/ZEO/zrpc/connection.py 1.1.2.2.2.1 => 1.1.2.2.2.2 === __super_close = smac.SizedMessageAsyncConnection.close __super_writable = smac.SizedMessageAsyncConnection.writable + __super_message_output = smac.SizedMessageAsyncConnection.message_output + + protocol_version = "Z200" def __init__(self, sock, addr, obj=None): self.obj = None @@ -88,6 +91,7 @@ self.__reply_lock = threading.Lock() self.__reply_lock.acquire() self.register_object(obj) + self.handshake() def __repr__(self): return "<%s %s>" % (self.__class__.__name__, self.addr) @@ -108,6 +112,25 @@ """Register obj as the true object to invoke methods on""" self.obj = obj + def handshake(self): + # When a connection is created the first message sent is a + # 4-byte protocol version. This mechanism should allow the + # protocol to evolve over time, and let servers handle clients + # using multiple versions of the protocol. + + # The mechanism replace the message_input() method for the + # first message received. + + # The client sends the protocol version it is using. + self._message_input = self.message_input + self.message_input = self.recv_handshake + self.message_output(self.protocol_version) + + def recv_handshake(self, message): + if message == self.protocol_version: + self.message_input = self._message_input + # otherwise do something else... + def message_input(self, message): """Decoding an incoming message and dispatch it""" # XXX Not sure what to do with errors that reach this level. @@ -298,8 +321,9 @@ class ServerConnection(Connection): """Connection on the server side""" - # XXX Do we need this class anymore? + # The server side does not send a protocol message. Instead, it + # adapts to whatever the client sends it. class ManagedServerConnection(ServerConnection): """A connection that notifies its ConnectionManager of closing""" === StandaloneZODB/ZEO/zrpc/marshal.py 1.1.2.1.2.1 => 1.1.2.1.2.2 === import cPickle from cStringIO import StringIO +import struct import types class Marshaller: @@ -30,6 +31,8 @@ cPickle.PickleError, cPickle.PicklingError) + VERSION = 1 + def encode(self, msgid, flags, name, args): """Returns an encoded message""" return self.pickle((msgid, flags, name, args), 1) @@ -41,10 +44,10 @@ try: return unpickler.load() # msgid, flags, name, args - except (cPickle.UnpicklingError, IndexError), err_msg: + except (self.errors, IndexError), err_msg: log("can't decode %s" % repr(msg), level=zLOG.ERROR) raise DecodingError(msg) - + _globals = globals() _silly = ('__doc__',) From jeremy at zope.com Fri Apr 26 15:26:00 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientStorage.py:1.35.6.4.2.2 Message-ID: <200204261926.g3QJQ0d11433@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv11377 Modified Files: Tag: ZEO2-branch ClientStorage.py Log Message: First step words protocol negotiation. New client sends a 4-byte protocol id to the server. XXX Is this sufficient for now? Also, rename "wait_for_server_on_startup" to "wait". This change affects a ctor calls in a bunch of files. === StandaloneZODB/ZEO/ClientStorage.py 1.35.6.4.2.1 => 1.35.6.4.2.2 === name='', client='', debug=0, var=None, min_disconnect_poll=5, max_disconnect_poll=300, - wait_for_server_on_startup=0, read_only=0): + wait=0, read_only=0): self._server = disconnected_stub self._is_read_only = read_only @@ -100,7 +100,7 @@ # XXX What if we can only get a read-only connection and we # want a read-write connection? Looks like the current code # will block forever. (Future feature) - if wait_for_server_on_startup: + if wait: self._rpc_mgr.connect(sync=1) else: if not self._rpc_mgr.attempt_connect(): @@ -152,6 +152,9 @@ def notifyConnected(self, c): log2(INFO, "Connected to storage via %s" % repr(c)) + + # check the protocol version here? + stub = ServerStub.StorageServer(c) self._oids = [] From jeremy at zope.com Mon Apr 29 18:33:04 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO/zrpc - connection.py:1.1.2.2.2.3 Message-ID: <200204292233.g3TMX4d27072@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO/zrpc In directory cvs.zope.org:/tmp/cvs-serv27061/zrpc Modified Files: Tag: ZEO2-branch connection.py Log Message: Reformat for readability. === StandaloneZODB/ZEO/zrpc/connection.py 1.1.2.2.2.2 => 1.1.2.2.2.3 === def handle_request(self, msgid, flags, name, args): if not self.check_method(name): - raise ZRPCError("Invalid method name: %s on %s" % (name, - `self.obj`)) + msg = "Invalid method name: %s on %s" % (name, repr(self.obj)) + raise ZRPCError(msg) meth = getattr(self.obj, name) try: From jeremy at zope.com Mon Apr 29 18:36:26 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - ClientStorage.py:1.35.6.4.2.3 ClientStub.py:1.3.2.2.2.2 Message-ID: <200204292236.g3TMaQu27755@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv27490 Modified Files: Tag: ZEO2-branch ClientStorage.py ClientStub.py Log Message: Replace serialno() metho with serialnos(). The storage server sent the client new serialnos for updated objects with the serialno() method. Change the interface to take a list of oid, serialno pairs instead of a single pair. This reduces the number of messages sent for multi-object commits, but has only a small effect on msg size for a single-object commit. Bug fixed: If tpc_begin() is called with a tid, honor it. === StandaloneZODB/ZEO/ClientStorage.py 1.35.6.4.2.2 => 1.35.6.4.2.3 === raise ClientDisconnected() - self._ts = get_timestamp(self._ts) - id = `self._ts` + if tid is None: + self._ts = get_timestamp(self._ts) + id = `self._ts` + else: + self._ts = TimeStamp(tid) + id = tid self._transaction = transaction try: @@ -452,8 +456,8 @@ # below are methods invoked by the StorageServer - def serialno(self, arg): - self._serials.append(arg) + def serialnos(self, args): + self._serials.extend(args) def info(self, dict): self._info.update(dict) === StandaloneZODB/ZEO/ClientStub.py 1.3.2.2.2.1 => 1.3.2.2.2.2 === self.rpc.callAsync('end') - def serialno(self, arg): - self.rpc.callAsync('serialno', arg) + def serialnos(self, arg): + self.rpc.callAsync('serialnos', arg) def info(self, arg): self.rpc.callAsync('info', arg) From jeremy at zope.com Mon Apr 29 18:36:46 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - CommitLog.py:1.1.2.1 Message-ID: <200204292236.g3TMakM27773@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv27762 Added Files: Tag: ZEO2-branch CommitLog.py Log Message: A new log for use with delayed commits. === Added File StandaloneZODB/ZEO/CommitLog.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 # ############################################################################## """Log a transaction's commit info during two-phase commit. A storage server allows multiple clients to commit transactions, but must serialize them as the actually execute at the server. The concurrent commits are achieved by logging actions up until the tpc_vote(). At that point, the entire transaction is committed on the real storage. """ import cPickle import tempfile class CommitLog: def __init__(self): self.file = tempfile.TemporaryFile(suffix=".log") self.pickler = cPickle.Pickler(self.file, 1) self.pickler.fast = 1 self.stores = 0 self.read = 0 def tpc_begin(self, t, tid, status): self.t = t self.tid = tid self.status = status def store(self, oid, serial, data, version): self.pickler.dump((oid, serial, data, version)) self.stores += 1 def get_loader(self): self.read = 1 self.file.seek(0) return self.stores, cPickle.Unpickler(self.file) From jeremy at zope.com Mon Apr 29 18:41:28 2002 From: jeremy at zope.com (Jeremy Hylton) Date: Sun Aug 10 16:31:20 2008 Subject: [ZEO-Checkins] CVS: StandaloneZODB/ZEO - StorageServer.py:1.32.6.3.2.2 Message-ID: <200204292241.g3TMfSc29065@cvs.baymountain.com> Update of /cvs-repository/StandaloneZODB/ZEO In directory cvs.zope.org:/tmp/cvs-serv29054 Modified Files: Tag: ZEO2-branch StorageServer.py Log Message: Remove distributed commit lock! Actually, just move it around a bit. Instead of blocking a client as soon as it reaches tpc_begin(), accept messages and queue them until the client calls a method that requires a response -- tpc_vote(), transactionalUndo(), abortVersion(), or commitVersion(). This lets one client send updates while another client is committing. In practice undo & versions are uncommon, so most transactions will eventually block on the vote. The new approach requires substantial changes to the implementation. The code now uses the Strategy pattern, as explained by this comment block: # A ZEOStorage instance can use different strategies to commit a # transaction. The current implementation uses different strategies # depending on whether the underlying storage is available. These # strategies implement the distributed commit lock. # If the underlying storage is availabe, start the commit immediately # using the ImmediateCommitStrategy. If the underlying storage is not # available because another client is committing a transaction, delay # the commit as long as possible. At some point it will no longer be # possible to delay; either the transaction will reach the vote stage # or a synchronous method like transactionalUndo() will be called. # When it is no longer possible to delay, the client must block until # the storage is ready. Then we switch back to the immediate strategy. === StandaloneZODB/ZEO/StorageServer.py 1.32.6.3.2.1 => 1.32.6.3.2.2 === from ZEO import ClientStub +from ZEO.CommitLog import CommitLog from ZEO.zrpc.server import Dispatcher from ZEO.zrpc.connection import ManagedServerConnection, Delay @@ -35,6 +36,7 @@ TransactionError, ReadOnlyError from ZODB.referencesf import referencesf from ZODB.Transaction import Transaction +from ZODB.TmpStore import TmpStore # We create a special fast pickler! This allows us # to create slightly more efficient pickles and @@ -47,6 +49,13 @@ error=None): zLOG.LOG(label, level, message, error=error) +# a version of log that includes the storage name +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) + zLOG.LOG("ZEO Server:%s:%s" % (pid, name), level, msg, error=error) + class StorageServerError(StorageError): pass @@ -55,6 +64,8 @@ # XXX should read_only be a per-storage option? not yet... self.addr = addr self.storages = storages + for s in storages.values(): + s._waiting = [] self.read_only = read_only self.connections = {} self.dispatcher = Dispatcher(addr, factory=self.newConnection, @@ -73,9 +84,6 @@ l = self.connections.get(storage_id) if l is None: l = self.connections[storage_id] = [] - # intialize waiting list - # XXX why are we using a mangled name ?!? - self.storages[storage_id]._ZEOStorage__waiting = [] l.append(proxy) def invalidate(self, conn, storage_id, invalidated=(), info=0): @@ -166,6 +174,7 @@ This method must be the first one called by the client. """ + self._log("register(%s, %s)" % (storage_id, read_only)) storage = self.server.storages.get(storage_id) if storage is None: self._log("unknown storage_id: %s" % storage_id) @@ -247,71 +256,11 @@ self.server.invalidate(0, self.__storage_id, (), self.get_size_info()) - def abortVersion(self, src, id): - self._check_tid(id, exc=StorageTransactionError) - oids = self.__storage.abortVersion(src, self._transaction) - for oid in oids: - self.__invalidated.append((oid, src)) - return oids - - def commitVersion(self, src, dest, id): - self._check_tid(id, exc=StorageTransactionError) - oids = self.__storage.commitVersion(src, dest, self._transaction) - for oid in oids: - self.__invalidated.append((oid, dest)) - if dest: - self.__invalidated.append((oid, src)) - return oids - - def storea(self, oid, serial, data, version, id): - self._check_tid(id, exc=StorageTransactionError) - # XXX The try/except seems to be doing a lot of work. How - # worried are we about errors that can't be pickled. - try: - newserial = self.__storage.store(oid, serial, data, version, - self._transaction) - except TransactionError, v: - # This is a normal transaction error such as a conflict error - # or a version lock or conflict error. It doesn't need to be - # logged. - self._log("transaction error: %s" % repr(v)) - newserial = v - except: - # all errors need to be serialized to prevent unexpected - # returns, which would screw up the return handling. - # IOW, Anything that ends up here is evil enough to be logged. - error = sys.exc_info() - self._log('store error: %s: %s' % (error[0], error[1]), - zLOG.ERROR, error=error) - newserial = error[1] - del error - else: - if serial != '\0\0\0\0\0\0\0\0': - self.__invalidated.append((oid, version)) - - # Is all this error checking necessary? - try: - nil = dump(newserial, 1) - except: - self._log("couldn't pickle newserial: %s" % repr(newserial), - zLOG.ERROR) - dump('', 1) # clear pickler - r = StorageServerError("Couldn't pickle exception %s" % \ - `newserial`) - newserial = r - - self.client.serialno((oid, newserial)) - - def vote(self, id): - self._check_tid(id, exc=StorageTransactionError) - self.__storage.tpc_vote(self._transaction) - - def transactionalUndo(self, trans_id, id): - self._check_tid(id, exc=StorageTransactionError) - oids = self.__storage.transactionalUndo(trans_id, self._transaction) - for oid in oids: - self.__invalidated.append((oid, None)) - return oids + def new_oids(self, n=100): + """Return a sequence of n new oids, where n defaults to 100""" + if n < 0: + n = 1 + return [self.__storage.new_oid() for i in range(n)] def undo(self, transaction_id): oids = self.__storage.undo(transaction_id) @@ -321,18 +270,6 @@ return oids return () - # When multiple clients are using a single storage, there are several - # different _transaction attributes to keep track of. Each - # StorageProxy object has a single _transaction that refers to its - # current transaction. The storage (self.__storage) has another - # _transaction that is used for the *real* transaction. - - # The real trick comes with the __waiting queue for a storage. - # When a StorageProxy pulls a new transaction from the queue, it - # must inform the new transaction's proxy. (The two proxies may - # be the same.) The new transaction's proxy sets its _transaction - # and continues from there. - def tpc_begin(self, id, user, description, ext, tid, status): if self._transaction is not None: if self._transaction.id == id: @@ -342,63 +279,261 @@ raise StorageTransactionError("Multiple simultaneous tpc_begin" " requests from one client.") + if self.__storage._transaction is None: + self.strategy = ImmediateCommitStrategy(self.__storage, + self.client) + else: + self.strategy = DelayedCommitStrategy(self.__storage, + self.wait) + t = Transaction() t.id = id t.user = user t.description = description t._extension = ext - if self.__storage._transaction is not None: - d = Delay() - self.__storage.__waiting.append((d, self, t, tid, status)) - return d - + self.strategy.tpc_begin(t, tid, status) self._transaction = t - self.__storage.tpc_begin(t, tid, status) - self.__invalidated = [] def tpc_finish(self, id): if not self._check_tid(id): return - - r = self.__storage.tpc_finish(self._transaction) - assert self.__storage._transaction is None - - if self.__invalidated: + invalidated = self.strategy.tpc_finish() + if invalidated: self.server.invalidate(self, self.__storage_id, - self.__invalidated, - self.get_size_info()) - + self.__invalidated, self.get_size_info()) if not self._handle_waiting(): self._transaction = None - self.__invalidated = [] + self.strategy = None def tpc_abort(self, id): if not self._check_tid(id): return - r = self.__storage.tpc_abort(self._transaction) - assert self.__storage._transaction is None - + self.strategy.tpc_abort() if not self._handle_waiting(): self._transaction = None - self.__invalidated = [] + self.strategy = None - def _restart_delayed_transaction(self, delay, trans, tid, status): - self._transaction = trans - self.__storage.tpc_begin(trans, tid, status) - self.__invalidated = [] - assert self._transaction.id == self.__storage._transaction.id - delay.reply(None) + # XXX handle new serialnos + + def storea(self, oid, serial, data, version, id): + self._check_tid(id, exc=StorageTransactionError) + self.strategy.store(oid, serial, data, version) + + def vote(self, id): + self._check_tid(id, exc=StorageTransactionError) + return self.strategy.tpc_vote() + + def abortVersion(self, src, id): + self._check_tid(id, exc=StorageTransactionError) + return self.strategy.abortVersion(src) + + def commitVersion(self, src, dest, id): + self._check_tid(id, exc=StorageTransactionError) + return self.strategy.commitVersion(src, dest) + + def transactionalUndo(self, trans_id, id): + self._check_tid(id, exc=StorageTransactionError) + return self.strategy.transactionalUndo(trans_id) + + # When a delayed transaction is restarted, the dance is + # complicated. The restart occurs when one ZEOStorage instance + # finishes as a transaction and finds another instance is in the + # _waiting list. + + # XXX It might be better to have a mechanism to explicitly send + # the finishing transaction's reply before restarting the waiting + # transaction. If the restart takes a long time, the previous + # client will be blocked until it finishes. + + def wait(self): + d = Delay() + self.__storage._waiting.append((d, self)) + return d def _handle_waiting(self): - if self.__storage.__waiting: - delay, proxy, trans, tid, status = self.__storage.__waiting.pop(0) - proxy._restart_delayed_transaction(delay, trans, tid, status) - if self is proxy: - return 1 + if self.__storage._waiting: + delay, zeo_storage = self.__storage._waiting.pop(0) + self.restart(delay) + zeo_storage.restart(delay) + + def restart(self, delay): + old_strategy = self.strategy + self.strategy = ImmediateCommitStrategy(self.__storage, + self.client) + delay.reply(old_strategy.restart(self.strategy)) + +# A ZEOStorage instance can use different strategies to commit a +# transaction. The current implementation uses different strategies +# depending on whether the underlying storage is available. These +# strategies implement the distributed commit lock. + +# If the underlying storage is availabe, start the commit immediately +# using the ImmediateCommitStrategy. If the underlying storage is not +# available because another client is committing a transaction, delay +# the commit as long as possible. At some point it will no longer be +# possible to delay; either the transaction will reach the vote stage +# or a synchronous method like transactionalUndo() will be called. +# When it is no longer possible to delay, the client must block until +# the storage is ready. Then we switch back to the immediate strategy. + +class ICommitStrategy: + """A class that describes that commit strategy interface. + + The commit strategy interface does not require the transaction + argument, except for tpc_begin(). The storage interface requires + the client to pass a transaction object/id to each transactional + method. The strategy does not; it requires the caller to only + call methods for a single transaction. + """ + # This isn't a proper Zope interface, because I don't want to + # introduce a dependency between ZODB and Zope interfaces. + + def tpc_begin(self, trans, tid, status): pass + + def store(self, oid, serial, data, version): pass + + def abortVersion(self, src): pass + + def commitVersion(self, src, dest): pass + + # the trans_id arg to transactionalUndo is not the current txn's id + def transactionalUndo(self, trans_id): pass + + def tpc_vote(self): pass + + def tpc_abort(self): pass + + def tpc_finish(self): pass + +class ImmediateCommitStrategy: + """The storage is available so do a normal commit.""" + + def __init__(self, storage, client): + self.storage = storage + self.client = client + self.invalidated = [] + self.serials = [] + + def tpc_begin(self, txn, tid, status): + self.txn = txn + self.storage.tpc_begin(txn, tid, status) + + def tpc_vote(self): + # send all the serialnos as a batch + self.client.serialnos(self.serials) + return self.storage.tpc_vote(self.txn) + + def tpc_finish(self): + self.storage.tpc_finish(self.txn) + return self.invalidated - def new_oids(self, n=100): - """Return a sequence of n new oids, where n defaults to 100""" - if n < 0: - n = 1 - return [self.__storage.new_oid() for i in range(n)] + def tpc_abort(self): + self.storage.tpc_abort(self.txn) + + def store(self, oid, serial, data, version): + try: + newserial = self.storage.store(oid, serial, data, version, + self.txn) + except TransactionError, err: + # Storage errors are passed to the client + newserial = err + except: + # Unexpected storage errors are logged and passed to the client + exc_info = sys.exc_info() + slog(self.storage, "store error: %s, %s" % exc_info[:2], + zLOG.ERROR, error=exc_info) + newserial = exc_info[1] + del exc_info + else: + if serial != "\0\0\0\0\0\0\0\0": + self.invalidated.append((oid, version)) + + try: + nil = dump(newserial, 1) + except: + msg = "Couldn't pickle storage exception: %s" % repr(newserial) + slog(self.storage, msg, zLOG.ERROR) + dump('', 1) # clear pickler + r = StorageServerError(msg) + newserial = r + self.serials.append((oid, newserial)) + + def commitVersion(self, src, dest): + oids = self.storage.commitVersion(src, dest, self.txn) + inv = [(oid, dest) for oid in oids] + self.invalidated.extend(inv) + if dest: + inv = [(oid, src) for oid in oids] + self.invalidated.extend(inv) + return oids + + def abortVersion(self, src): + oids = self.storage.abortVersion(src, self.txn) + inv = [(oid, src) for oid in oids] + self.invalidated.extend(inv) + return oids + + def transactionalUndo(self, trans_id): + oids = self.storage.transactionalUndo(trans_id, self.txn) + inv = [(oid, None) for oid in oids] + self.invalidated.extend(inv) + return oids + +class DelayedCommitStrategy: + """The storage is unavailable, so log to a file.""" + + def __init__(self, storage, block): + # the block argument is called when we can't delay any longer + self.storage = storage + self.block = block + self.log = CommitLog() + self.invalidated = [] + + # Store information about the call that blocks + self.name = None + self.args = None + + def tpc_begin(self, txn, tid, status): + self.txn = txn + self.tid = tid + self.status = status + + def store(self, oid, serial, data, version): + self.log.store(oid, serial, data, version) + + def tpc_abort(self): + pass # just forget about this strategy + + def tpc_finish(self): + raise RuntimeError, "Logic error. This method must not be called." + + def tpc_vote(self): + self.name = "tpc_vote" + self.args = () + return self.block() + + def commitVersion(self, src, dest): + self.name = "commitVersion" + self.args = src, dest + return self.block() + + def abortVersion(self, src): + self.name = "abortVersion" + self.args = src, + return self.block() + + def transactionalUndo(self, trans_id): + self.name = "transactionalUndo" + self.args = trans_id, + return self.block() + + def restart(self, new_strategy): + # called by the storage when the storage is available + new_strategy.tpc_begin(self.txn, self.tid, self.status) + loads, loader = self.log.get_loader() + for i in len(loads): + oid, serial, data, version = loader.load() + new_strategy.store(oid, serial, data, version) + meth = getattr(new_strategy, self.name) + return meth(*self.args)