Commit 13c1b2d3 authored by Jeremy Hylton's avatar Jeremy Hylton

Rationalize disconnected exceptions so there is one root exception.

ZEO.Exceptions.ClientDisconnected will always be raised when a client
is disconnected.  There's also a subclass of this exception in
ZEO.zrpc.error so that it's possible to distinguish whether the error
occurred in the RPC layer or at the storage layer.
parent c17b365c
......@@ -16,15 +16,8 @@
Public contents of this module:
ClientStorage -- the main class, implementing the Storage API
ClientStorageError -- exception raised by ClientStorage
UnrecognizedResult -- exception raised by ClientStorage
ClientDisconnected -- exception raised by ClientStorage
"""
# XXX TO DO
# set self._storage = stub later, in endVerify
# if wait is given, wait until verify is complete
import cPickle
import os
import socket
......@@ -35,7 +28,8 @@ import types
from ZEO import ClientCache, ServerStub
from ZEO.TransactionBuffer import TransactionBuffer
from ZEO.Exceptions import Disconnected
from ZEO.Exceptions \
import ClientStorageError, UnrecognizedResult, ClientDisconnected
from ZEO.zrpc.client import ConnectionManager
from ZODB import POSException
......@@ -50,15 +44,6 @@ try:
except ImportError:
ResolvedSerial = 'rs'
class ClientStorageError(POSException.StorageError):
"""An error occured in the ZEO Client Storage."""
class UnrecognizedResult(ClientStorageError):
"""A server call returned an unrecognized result."""
class ClientDisconnected(ClientStorageError, Disconnected):
"""The database storage is disconnected from the storage."""
def tid2time(tid):
return str(TimeStamp(tid))
......@@ -303,7 +288,7 @@ class ClientStorage:
self._ready.wait(30)
if self._ready.isSet():
break
log2(INFO, "Waiting to connect to server")
log2(INFO, "Wait for cache verification to finish")
else:
# If there is no mainloop running, this code needs
# to call poll() to cause asyncore to handle events.
......@@ -317,7 +302,7 @@ class ClientStorage:
cn.pending(30)
if self._ready.isSet():
break
log2(INFO, "Waiting to connect to server")
log2(INFO, "Wait for cache verification to finish")
def close(self):
"""Storage API: finalize the storage, releasing external resources."""
......
......@@ -13,6 +13,14 @@
##############################################################################
"""Exceptions for ZEO."""
class Disconnected(Exception):
"""Exception raised when a ZEO client is disconnected from the
ZEO server."""
from ZODB.POSException import StorageError
class ClientStorageError(StorageError):
"""An error occured in the ZEO Client Storage."""
class UnrecognizedResult(ClientStorageError):
"""A server call returned an unrecognized result."""
class ClientDisconnected(ClientStorageError):
"""The database storage is disconnected from the storage."""
......@@ -21,7 +21,7 @@ from ZODB.TimeStamp import TimeStamp
from ZODB.tests.StorageTestBase import zodb_pickle, MinPO
import ZEO.ClientStorage
from ZEO.Exceptions import Disconnected
from ZEO.Exceptions import ClientDisconnected
from ZEO.tests.TestThread import TestThread
ZERO = '\0'*8
......@@ -56,7 +56,7 @@ class WorkerThread(TestThread):
self.storage.tpc_finish(self.trans)
else:
self.storage.tpc_abort(self.trans)
except Disconnected:
except ClientDisconnected:
pass
def myvote(self):
......
......@@ -27,7 +27,7 @@ import time
import zLOG
from ZEO.ClientStorage import ClientStorage
from ZEO.Exceptions import Disconnected
from ZEO.Exceptions import ClientDisconnected
from ZEO.zrpc.marshal import Marshaller
from ZEO.tests import forker
......@@ -200,7 +200,7 @@ class ConnectionTests(CommonSetupTearDown):
try:
self._dostore()
break
except Disconnected:
except ClientDisconnected:
self._storage.sync()
time.sleep(0.5)
......@@ -264,7 +264,7 @@ class ConnectionTests(CommonSetupTearDown):
# Poll until the client disconnects
self.pollDown()
# Stores should fail now
self.assertRaises(Disconnected, self._dostore)
self.assertRaises(ClientDisconnected, self._dostore)
# Restart the server
self.startServer(create=0)
......@@ -274,12 +274,13 @@ class ConnectionTests(CommonSetupTearDown):
self._dostore()
def checkDisconnectionError(self):
# Make sure we get a Disconnected when we try to read an
# Make sure we get a ClientDisconnected when we try to read an
# object when we're not connected to a storage server and the
# object is not in the cache.
self.shutdownServer()
self._storage = self.openClientStorage('test', 1000, wait=0)
self.assertRaises(Disconnected, self._storage.load, 'fredwash', '')
self.assertRaises(ClientDisconnected,
self._storage.load, 'fredwash', '')
def checkBasicPersistence(self):
# Verify cached data persists across client storage instances.
......@@ -345,10 +346,8 @@ class ConnectionTests(CommonSetupTearDown):
try:
self._dostore(oid, data=obj)
break
except Disconnected:
except ClientDisconnected:
# Maybe the exception mess is better now
## except (Disconnected, select.error,
## threading.ThreadError, socket.error):
zLOG.LOG("checkReconnection", zLOG.INFO,
"Error after server restart; retrying.",
error=sys.exc_info())
......@@ -389,7 +388,7 @@ class ConnectionTests(CommonSetupTearDown):
try:
self._dostore()
except Disconnected:
except ClientDisconnected:
pass
else:
self._storage.close()
......@@ -504,7 +503,7 @@ class ReconnectionTests(CommonSetupTearDown):
# Poll until the client disconnects
self.pollDown()
# Stores should fail now
self.assertRaises(Disconnected, self._dostore)
self.assertRaises(ClientDisconnected, self._dostore)
# Restart the server
self.startServer(create=0, read_only=1)
......@@ -533,7 +532,7 @@ class ReconnectionTests(CommonSetupTearDown):
# Poll until the client disconnects
self.pollDown()
# Stores should fail now
self.assertRaises(Disconnected, self._dostore)
self.assertRaises(ClientDisconnected, self._dostore)
# Restart the server, this time read-write
self.startServer(create=0)
......@@ -566,7 +565,7 @@ class ReconnectionTests(CommonSetupTearDown):
try:
self._dostore()
break
except (Disconnected, ReadOnlyError):
except (ClientDisconnected, ReadOnlyError):
# If the client isn't connected at all, sync() returns
# quickly and the test fails because it doesn't wait
# long enough for the client.
......@@ -691,7 +690,7 @@ class TimeoutTests(CommonSetupTearDown):
storage.tpc_begin(txn)
storage.tpc_vote(txn)
time.sleep(2)
self.assertRaises(Disconnected, storage.tpc_finish, txn)
self.assertRaises(ClientDisconnected, storage.tpc_finish, txn)
def checkTimeoutOnAbort(self):
storage = self.openClientStorage()
......
......@@ -19,7 +19,7 @@ from ZODB.Transaction import Transaction
from ZODB.tests.StorageTestBase import zodb_pickle, MinPO
import ZEO.ClientStorage
from ZEO.Exceptions import Disconnected
from ZEO.Exceptions import ClientDisconnected
ZERO = '\0'*8
......@@ -86,7 +86,7 @@ class AbortsAfterBeginFailsThread(BasicThread):
self.gotValueError = 1
try:
self.storage.tpc_abort(self.trans)
except Disconnected:
except ClientDisconnected:
self.gotDisconnected = 1
......
......@@ -39,7 +39,6 @@ from ZODB.tests import StorageTestBase, BasicStorage, VersionStorage, \
# ZEO imports
from ZEO.ClientStorage import ClientStorage
from ZEO.Exceptions import Disconnected
# ZEO test support
from ZEO.tests import forker, Cache
......
......@@ -12,10 +12,16 @@
#
##############################################################################
from ZODB import POSException
from ZEO.Exceptions import Disconnected
from ZEO.Exceptions import ClientDisconnected
class ZRPCError(POSException.StorageError):
pass
class DisconnectedError(ZRPCError, Disconnected):
"""The database storage is disconnected from the storage server."""
class DisconnectedError(ZRPCError, ClientDisconnected):
"""The database storage is disconnected from the storage server.
The error occurred because a problem in the low-level RPC connection,
or because the connection was closed.
"""
# This subclass is raised when zrpc catches the error.
......@@ -15,11 +15,11 @@
import asyncore, struct
import threading
from ZEO.Exceptions import Disconnected
import zLOG
from types import StringType
from ZEO.zrpc.log import log, short_repr
from ZEO.zrpc.error import DisconnectedError
import zLOG
import socket, errno
......@@ -209,10 +209,8 @@ class SizedMessageAsyncConnection(asyncore.dispatcher):
level=zLOG.TRACE)
if self.__closed:
raise Disconnected, (
"This action is temporarily unavailable."
"<p>"
)
raise DisconnectedError(
"This action is temporarily unavailable.<p>")
self.__output_lock.acquire()
try:
# do two separate appends to avoid copying the message string
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment