[Zodb-checkins] CVS: ZEO - .cvsignore:1.2 LICENSE.txt:1.2 README.txt:1.2 setup.py:1.2 test.py:1.2 CHANGES.txt:1.29
Jeremy Hylton
jeremy@zope.com
Tue, 11 Jun 2002 09:43:37 -0400
Update of /cvs-repository/ZEO
In directory cvs.zope.org:/tmp/cvs-serv5548
Modified Files:
CHANGES.txt
Added Files:
.cvsignore LICENSE.txt README.txt setup.py test.py
Log Message:
Merge ZEO2-branch to trunk.
=== ZEO/.cvsignore 1.1 => 1.2 ===
=== ZEO/LICENSE.txt 1.1 => 1.2 ===
+-----------------------------------------------
+
+This software is Copyright (c) Zope Corporation (tm) and
+Contributors. All rights reserved.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+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. The name Zope Corporation (tm) must not be used to
+ endorse or promote products derived from this software
+ without prior written permission from Zope Corporation.
+
+4. The right to distribute this software or to use it for
+ any purpose does not give you the right to use Servicemarks
+ (sm) or Trademarks (tm) of Zope Corporation. Use of them is
+ covered in a separate agreement (see
+ http://www.zope.com/Marks).
+
+5. If any files are modified, you must cause the modified
+ files to carry prominent notices stating that you changed
+ the files and the date of any change.
+
+Disclaimer
+
+ THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``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 ZOPE CORPORATION 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 Zope
+Corporation and many individuals on behalf of Zope
+Corporation. Specific attributions are listed in the
+accompanying credits file.
=== ZEO/README.txt 1.1 => 1.2 ===
+
+ 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/.
+
+ IMPORTANT: ZEO version 2 is not backwards compatible with ZEO 1.0.
+ A system that uses ZEO must upgrade all clients and servers at the
+ same time.
+
+ The ZEO package is contained in the directory named ZEO.
+
+ If you are using Zope, see doc/ZopeREADME.txt; otherwise, see
+ doc/NonZopeREADME.txt.
=== ZEO/setup.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+from distutils.core import setup
+
+packages = ['ZEO', 'ZEO.zrpc', 'ZEO.tests']
+
+setup(name="ZEO",
+ version="2.0a1",
+ description="Zope Enterprise Objects",
+ maintainer="Zope Corp.",
+ maintainer_email="zodb-dev@zope.org",
+ url = "http://www.zope.org/Products/ZEO",
+
+ packages = packages,
+ )
=== ZEO/test.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+"""Test harness for ZEO
+
+usage: python test.py [options] [modulepath] [testcase]
+
+options:
+ -v -- verbose (can be repeated to increase verbosity)
+ -b -- run "setup.py -q build" before running the tests
+ -d -- run tests in debug mode
+ -L -- run tests in an infinite loop
+ -h -- print this message
+
+The optional modulepath and testcase arguments are regular expressions
+that can be used to limit the number of tests that are run. The
+modulepath regex must be found in the path of the module that contains
+the tests. The testcase regex must be found in the name of the test case.
+
+When it finishes, the test harness prints a report of the tests run
+and how long it took. If errors or failures occured, they will be
+reported along with a traceback. If one -v is specified, a dot will
+be printed as each test is run. If two -v's are specified, the name
+of each test will be printed as it runs.
+"""
+
+import os
+import re
+import sys
+import traceback
+import unittest
+
+from distutils.util import get_platform
+
+class ImmediateTestResult(unittest._TextTestResult):
+
+ def _print_traceback(self, msg, err, test, errlist):
+ if self.showAll or self.dots:
+ self.stream.writeln("\n")
+
+ tb = ''.join(traceback.format_exception(*err))
+ self.stream.writeln(msg)
+ self.stream.writeln(tb)
+ errlist.append((test, tb))
+
+ def addError(self, test, err):
+ self._print_traceback("Error in test %s" % test, err,
+ test, self.errors)
+
+ def addFailure(self, test, err):
+ self._print_traceback("Failure in test %s" % test, err,
+ test, self.failures)
+
+ def printErrorList(self, flavor, errors):
+ for test, err in errors:
+ self.stream.writeln(self.separator1)
+ self.stream.writeln("%s: %s" % (flavor, self.getDescription(test)))
+ self.stream.writeln(self.separator2)
+ self.stream.writeln(err)
+
+
+class ImmediateTestRunner(unittest.TextTestRunner):
+
+ def _makeResult(self):
+ return ImmediateTestResult(self.stream, self.descriptions,
+ self.verbosity)
+
+# setup list of directories to put on the path
+
+PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3])
+
+def setup_path():
+ DIRS = ["lib",
+ "lib.%s" % PLAT_SPEC,
+ ]
+ for d in DIRS:
+ sys.path.insert(0, d)
+
+
+# Find test files.
+# They live under either a lib.PLAT_SPEC or plain "lib" directory.
+_sep = re.escape(os.sep)
+_pat = "%s(%s|lib)%s" % (_sep, re.escape("lib." + PLAT_SPEC), _sep)
+hasgooddir = re.compile(_pat).search
+del _sep, _pat
+
+class TestFileFinder:
+ def __init__(self):
+ self.files = []
+
+ def visit(self, rx, dir, files):
+ if dir[-5:] != "tests":
+ return
+ # ignore tests that aren't in packages
+ if not "__init__.py" in files:
+ print "not a package", dir
+ return
+ for file in files:
+ if file[:4] == "test" and file[-3:] == ".py":
+ path = os.path.join(dir, file)
+ if not hasgooddir(path):
+ # built for a different version
+ continue
+ if rx is not None:
+ if rx.search(path):
+ self.files.append(path)
+ else:
+ self.files.append(path)
+
+def find_tests(filter):
+ if filter is not None:
+ rx = re.compile(filter)
+ else:
+ rx = None
+ finder = TestFileFinder()
+ os.path.walk("build", finder.visit, rx)
+ return finder.files
+
+def package_import(modname):
+ mod = __import__(modname)
+ for part in modname.split(".")[1:]:
+ mod = getattr(mod, part)
+ return mod
+
+def module_from_path(path):
+ """Return the Python package name indiciated by the filesystem path.
+
+ The path starts with build/lib or build /lib.mumble..."""
+
+ assert path[-3:] == '.py'
+ path = path[:-3]
+ dirs = []
+ while path:
+ path, end = os.path.split(path)
+ dirs.insert(0, end)
+ assert dirs[0] == "build"
+ assert dirs[1][:3] == "lib"
+ return ".".join(dirs[2:])
+
+def get_suite(file):
+ assert file[:5] == "build"
+ assert file[-3:] == '.py'
+ modname = module_from_path(file)
+ mod = package_import(modname)
+ try:
+ suite_factory = mod.test_suite
+ except AttributeError, err:
+ return None
+ return suite_factory()
+
+def match(rx, s):
+ if not rx:
+ return 1
+ if rx[0] == '!':
+ return re.search(rx[1:], s) is None
+ else:
+ return re.search(rx, s) is not None
+
+def filter_testcases(s, rx):
+ new = unittest.TestSuite()
+ for test in s._tests:
+ if isinstance(test, unittest.TestCase):
+ name = test.id() # Full test name: package.module.class.method
+ name = name[1 + name.rfind('.'):] # extract method name
+ if match(rx, name):
+ new.addTest(test)
+ else:
+ filtered = filter_testcases(test, rx)
+ if filtered:
+ new.addTest(filtered)
+ return new
+
+def runner(files, test_filter, debug):
+ runner = ImmediateTestRunner(verbosity=VERBOSE)
+ suite = unittest.TestSuite()
+ for file in files:
+ s = get_suite(file)
+ if s is not None:
+ if test_filter is not None:
+ s = filter_testcases(s, test_filter)
+ suite.addTest(s)
+ if debug:
+ suite.debug()
+ return 0
+ r = runner.run(suite)
+ return len(r.errors) + len(r.failures)
+
+def main(module_filter, test_filter):
+ setup_path()
+ files = find_tests(module_filter)
+ files.sort()
+
+ os.chdir("build")
+
+ if LOOP:
+ while 1:
+ runner(files, test_filter, debug)
+ else:
+ runner(files, test_filter, debug)
+
+if __name__ == "__main__":
+ import getopt
+
+ module_filter = None
+ test_filter = None
+ VERBOSE = 0
+ LOOP = 0
+ debug = 0 # Don't collect test results; simply let tests crash
+ build = 0
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], 'vdLbh')
+ except getopt.error, msg:
+ print msg
+ print "Try `python %s -h' for more information." % sys.argv[0]
+ sys.exit(2)
+
+ for k, v in opts:
+ if k == '-v':
+ VERBOSE = VERBOSE + 1
+ elif k == '-d':
+ debug = 1
+ elif k == '-L':
+ LOOP = 1
+ elif k == '-b':
+ build = 1
+ elif k == '-h':
+ print __doc__
+ sys.exit(0)
+
+ if build:
+ cmd = sys.executable + " setup.py -q build"
+ if VERBOSE:
+ print cmd
+ sts = os.system(cmd)
+ if sts:
+ print "Build failed", hex(sts)
+ sys.exit(1)
+
+ if args:
+ if len(args) > 1:
+ test_filter = args[1]
+ module_filter = args[0]
+ try:
+ bad = main(module_filter, test_filter)
+ if bad:
+ sys.exit(1)
+ except ImportError, err:
+ print err
+ print sys.path
+ raise
=== ZEO/CHANGES.txt 1.28 => 1.29 ===
+Revision History, Zope Enterprise Objects, version 2
- ZEO 1.0 final
+ ZEO 2.0 alpha 1
- Bugs fixed
-
- - Fixed a bug that prevented a client from reconnecting to a
- server if the server restarted.
-
- - Fixed start.py so that it prints a message on the console when
- it fails in addition to using zLOG.
-
- - Fleshed out installation instructions and version dependencies.
-
- ZEO 1.0 beta 3
-
- Bugs fixed
-
- - The previous beta failed to startup a connection to a server
- running any storage that did not support transactionalUndo.
- The server now checks for supported features in a way that will
- not cause errors.
-
- ZEO 1.0 beta 2
-
- New Features
-
- - Support for transactionalUndo when the underlying storage
- supports it.
-
- - A unit test suite was added. The test suite requires that
- PyUnit be installed; it's part of the standard library in
- Python 2.1. It also requires that the ZODB installation
- defines the ZODB.tests package. If these conditions don't
- hold, the test suite can't be run.
-
- Bugs fixed
-
- - A cache invalidation bug was fixed for commitVersion and
- abortVersion. It was possible for a load the occurred between
- a commit version and a tpc_finish to store invalid data in the
- cache.
-
- - The undoInfo() method defines default values for its arguments.
-
- - The final argument to tpc_begin(), the transaction extended
- metadata, was ignored.
-
- - A theoretical bug in the client caching code for objects
- created in versions was fixed.
-
- ZEO 1.0 beta 1
-
- New Features
-
- - Improved release organization.
-
- - Moved documentation and misc files out of the ZEO package into
- the release directory.
-
- Bugs fixed
-
- - Normal shutdown was reported as a panic.
-
- - The signal exception handler was disabled.
-
- - Errors arising from incompatable versions of cPickle were
- uclear.
-
-
- ZEO 0.5.0
-
- New Features
-
- - The server can be made to reopen it's log file
- by sending it a HUP (on systems supporting signals). Note
- that this requires a change to asyncore to catch interrupted
- system calls on some platforms.
-
- - The shutdown signals have been changed:
-
- o To shutdown, use TERM
-
- o To restart, use INT. (This must be send to the
- child, not the parent.
-
- - Client scripts can now be written to pack a remote storage and
- wait for the pack results. This is handy when packing as part
- of cron jobs.
-
- - It is no longer necessary to symbolically link cPickle or
- ZServer. ZServer is no longer necessary at all.
-
- - A Zope-style INSTANCE_HOME and var directory are no longer
- needed.
-
- - An option, -d, was added to facilitate generation of a
- detailed debug log while running in the background.
-
- - The documentation has been simplified and spread over multiple
- files in the doc subdirectory.
-
- Bugs Fixed
-
- - Application-level conflict resolution, introduced in Zope
- 2.3.1, was not supported. This caused the ZEO cache to be
- written incorrectly.
-
- - A possible (but unobserved) race condition that could
- lead to ZEO cache corruption was corrected.
-
- - ZEO clients could fail to start if they needed data that
- wasn't in their cache and if they couldn't talk to a ZEO
- server right away. For now, on startup, the client storage
- will wait to connect to a storage before returning from
- initialization.
-
- - Restarting the ZEO server shortly after shutting down could
- lead to "address already in use" errors.
-
- - User-level eceptions, like undo, version-lock, and conflict
- errors were logged in the server event log.
-
- - Pack errors weren't logged in the server event log.
-
- - If an attempt was made to commit a transaction with updates
- while the client storage was disconnected from the server,
- no further write transactions would be allowed, even after
- reconnection, and the site would eventually hang.
-
- - A forgotten argument made it unreliable to start a ClientStorage
- after the main loop has started.
-
- - In combination with recent changes in zdeamon, startup errors
- could cause infinite loops.
-
- - The handling of the Python global, __debug__, was not
- compatible with Python 2.1.
-
- - If an exception raised on the server which could not be
- unpickled on the client could cause the client connection to
- fail.
-
- Planned for (future) ZEO releases
-
- New Features
-
- - Provide optional data compression. This should enhance
- performance over slow connections to the storage server and
- reduce the server I/O load.
-
- - Provide optional authentication adapters that allow for
- pluggable authentication and encryption schemes.
-
- This is a feature that is listed on the ZEO fact sheet, but
- that didn't make it into the 1.0 release. Firewall or secure
- tunneling techniques can be used to secure communication
- between clients and the storage for now when the client and
- storage are on different machines. (If they are on the same
- machine, then unix-domain sockets or the loop-back interface
- can be used.)
-
- - Provide an option to start a client process without waiting
- for a connection to the storage server. This was the original
- intent, however, it turns out that it can be extremely
- problemantic to get storage errors resulting from attempts to
- read objects not in the cache during process (e.g. Zope)
- startup. In addition, some smarter cache management can be
- done to decrease the probability of important objects being
- removed from the cache.
-
- - Provide improved client cache management. This will involve
- changes like:
-
- o Increasing the number of cache files to reduce the number of
- objects lost from the cache (or that need to be recovered)
- when the cache "rolls over".
-
- o Use separate indexes for each cache.
-
- o use better cache indexing structures
-
- ZEO 0.4.1
-
- Bugs fixed
-
- - Improperly handled server exeptions could cause clients to
- lock up.
-
- - Misshandling of client transaction meta data could cause
- server errors because transaction ids were mangled.
-
- - The storage server didn't close sockets on shutdown. This
- could sometimes make it necessary to wait before restarting
- the server to avoid "address already in use" messages.
-
- - The storage server did not log shutdown.
-
- ZEO 0.4
-
- Bugs fixed
-
- - The new (in 0.3) logic to switch to an ordinary user when
- started as root was executed too late so that some files were
- incorrectly owned by root. This caused ZEO clients to fail
- when the cache files were rotated.
-
- - There were some unusual error conditions that were not handled
- correctly that could cause clients to fail. This was detected
- only when ZEO was put into production on zope.org.
-
- - The cache files weren't rotated on reads. This could cause the
- caches to grow way beyond their target sizes.
-
- - Exceptions raised in the servers asynchronous store handler
- could cause the client and server to get out of sync.
-
- - Connection and disconnection events weren't logged on the
- server.
-
- Features added
-
- - ClientStorage objects have two new constructor arguments,
- min_disconnect_poll and max_disconnect_poll to set the minimum
- and maximum times to wait, in seconds, before retrying to
- reconnect when disconnected from the ZEO server.
-
- - A call to get database info on startup was eliminated in
- favor of having the server send the information
- automatically. This eliminates a round-trip and, therefore
- speeds up startup a tiny bit.
-
- - Database size info is now sent to all clients (asynchronously)
- after a pack and after a transaction commit, allowing all
- clients to have timely size information.
-
- - Added client logging of connection attempts.
-
- - Added a misc subdirectory with sample storage server start and
- stop scripts and with a sample custom_zodb.py module.
-
- ZEO 0.3.0
-
- Bugs fixed
-
- - Large transactions (e.g. ZCatalog updates) could cause
- spurious conflict errors that could, eventually, make it
- impossible to modify some objects without restarting Zope.
-
- - Temporary non-persistent cache files were not removed at the
- end of a run.
-
- Features added
-
- - On Unix, when the storage server start script is run as root,
- the script will switch to a different user (nobody by
- default). There is a new '-u' option that can be used to
- specify the user.
-
- - On Unix the server will gracefully close served storages when
- the server is killed with a SIGTERM or SIGHUP. If a
- FileStorage is being served, then an index file will be
- written.
-
- ZEO 0.2.3
-
- Bugs fixed
-
- - Versions didn't work. Not even close. :|
-
- - If a client was disconnected from a server during transaction
- commit, then, when the client was reconnected to the server,
- attempts to commit transactions caused the client to hang.
-
- - The server would fail (and successfully automatically restart)
- if an unpickleable exception was raised.
-
- ZEO 0.2.2
-
- Bugs fixed
-
- - The storage server didn't fully implement a new ZODB storage
- protocol. This caused serving of FileStorages to fail in Zope
- 2.2.1, since FileStorages now use this protocol.
-
- - In the start.py start script
-
- o The '-S' option did not allow spaces between the option and it's
- argument.
-
- o The '-S' option did not work with FileStorages.
-
- o The README file didn't mention the '-S' option.
-
- ZEO 0.2.1
-
- Bugs fixed
-
- - ZEO clients didn't work properly (effectively at all) on
- Solaris or Windows NT.
-
- - An error in the handling of the distributed transaction lock
- could cause a client to stop writing and eventually hang if
- two clients tried to commit a transaction at the same time.
-
- - Extra (harmless) messages were sent from the server
- when invalidating objects during a commit.
-
- - New protocols (especially 'loadSerial'), used for looking at
- DTML historical versions, were not implemented.
-
- Features
-
- - The '-S' option was added to the storage server startup script
- to allow selection of one or more storages to serve.
-
- ZEO 0.2
-
- This release is expected to be close to beta quality. Initially, the
- primary goals of this release were to:
-
- - Correct some consistency problems that had been observed in
- 0.1 on starup.
-
- - Allow ZEO clients to detect, survive, and recover from
- disconnection from the ZEO server.
-
- Based on some feedback from some folks who tried 0.1, improving
- write performance was made a priority.
-
- Features
-
- - The ZEO Client now handles server failures gracefully:
-
- o The client with a persistent cache can generally startup
- even if the server is not running, assuming that it has at
- least a minimal number of objects in the cache.
-
- o The client will continue to function even if the server
- connection is interuppted.
-
- o Server availability is detected by the client (which tries
- to connect to the server every few minutes). A disconnected
- client will automatically reconnect to an available server.
-
- o When the client is disconnected, write transactions cannot
- be performed. Reads fail for objects that are not in the
- cache.
-
- - Performance enhancements
-
- The speed of write-intensive operations have been improved
- approximately 70%. When using Unix domain sockets for
- client/server communication, ZEO transactions take roughly 2-3
- times as long as FileStorage transactions to commit.
- (This was based on some tests. Your mileage may vary.)
-
- - Packing support was added. Note that packing is done
- asynchrounously. The client returns immediately from a pack
- call. The server packs in a thread and sends updated
- statistics to the client when packing is completed.
-
- - Support for Unix-domain sockets was added.
-
- - Pickles sent to the server are now checked to make sure that
- they don't contain unapproved instance or global-variable
- (function) pickles.
-
- Bugs fixed
-
- - Data could be badly inconsistent when a persistent cache
- was started, due to a bug in the cache initialization logic.
+ Brief overview of the differences between ZEO 1.0 and 2.0.
- - The application was allowed to begin operation while the cache
- was being verified. This could lead to harmful inconsistencies.
-
- Changes made to Zope to support ZEO
-
- - A number of changes were made to ZODB to support asynchronous
- storage during transaction commit.
-
- - Normally Zope updates the database during startup to reflect
- product changes. This behavior is now suppressed when the
- ZEO_CLIENT environment variable is set. It doesn't make sense
- for many clients to update the database for the same products.
+ - New protocol.
- - The asyncore module was modified to add support for multiple
- asyncore loops. This change was applied to asyncore in the
- Zope and the (official, owned by Sam Rushing) medusa CVS
- trees.
+ ZEO 2 uses a different wire protocol and a different API to
+ make RPC calls. The new protocol was designed to be flexible
+ and simple. It includes an initial handshake to set the
+ version number, which should allow future changes to the
+ protocol while reducing the difficulty of upgrades.
+
+ - Better handling of concurrent commits.
+
+ The ZEO server serializes concurrent commits to guarantee
+ consistency; the mechanism is often called the distributed
+ commit lock. ZEO 2 improves the efficiency of concurrent
+ commits by allowing data to be transferred to the server
+ before entering the commit lock.
- - A new module, ThreadedAsync.py has been added in the Zope
- lib/python directory. This module provides notification to
- async objects (like ZEO clients) to let them know when the
- asyncore main loop has started. This was needed to enable use
- of async code before the main loop starts.
+ - The ZEO client and server can be configured to operate in
+ read-only mode.
- ZEO 0.1 (aka "iteration 1")
+ - A ZEO client can be configured with multiple server addresses.
+ It uses the first server it can connect to.
- This was an initial alpha of ZEO that demonstrated basic
- functionalities. It lacked robustness and has some performance
- problems on writes.
+ - The wait_for_server_on_startup keyword argument to
+ ClientStorage has been renamed wait.