Commit 6e5bb8e1 authored by Jeremy Hylton's avatar Jeremy Hylton

Add minimal progress on debugger/recorder for ZEO.

Handing off to Barry.
parent 3b6c3dcb
##############################################################################
#
# Copyright (c) 2003 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 debugging version of the server that records network activity."""
from __future__ import nested_scopes
import struct
import time
from ZEO.StorageServer import StorageServer, ZEOStorage, log
from ZEO.zrpc.server import ManagedServerConnection
# a bunch of codes
NEW_CONN = 1
CLOSE_CONN = 2
DATA = 3
ERROR = 4
class DebugManagedServerConnection(ManagedServerConnection):
def __init__(self, sock, addr, obj, mgr):
# mgr is the DebugServer instance
self.mgr = mgr
self.__super_init(sock, addr, obj)
record_id = mgr._record_connection(addr)
self._record = lambda code, data: mgr._record(record_id, code, data)
self.obj.notifyConnected(self)
def close(self):
self._record(CLOSE_CONN, "")
ManagedServerConnection.close(self)
# override the lowest-level of asyncore's connection
def recv(self, buffer_size):
try:
data = self.socket.recv(buffer_size)
if not data:
# a closed connection is indicated by signaling
# a read condition, and having recv() return 0.
self.handle_close()
return ''
else:
self._record(DATA, data)
return data
except socket.error, why:
# winsock sometimes throws ENOTCONN
self._record(ERROR, why)
if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
self.handle_close()
return ''
else:
raise socket.error, why
class DebugServer(StorageServer):
ZEOStorageClass = DebugZEOStorage
ManagedServerConnectionClass = DebugManagerConnection
def __init__(self, *args, **kwargs):
StorageServer.__init__(*args, **kwargs)
self._setup_record(kwargs["record"])
self._conn_counter = 1
def _setup_record(self, path):
try:
self._recordfile = open(path, "ab")
except IOError, msg:
self._recordfile = None
log("failed to open recordfile %s: %s" % (path, msg))
def _record_connection(self, addr):
cid = self._conn_counter
self._conn_counter += 1
self._record(cid, NEW_CONN, str(addr))
return cid
def _record(self, conn, code, data):
s = struct.pack(">iii", code, time.time(), len(data)) + data
self._recordfile.write(s)
......@@ -23,6 +23,7 @@ Options:
-f/--filename FILENAME -- filename for FileStorage
-h/--help -- print this usage message and exit
-m/--monitor ADDRESS -- address of monitor server
-r/--record -- path of file to record low-level network activity
Unless -C is specified, -a and -f are required.
"""
......@@ -176,18 +177,20 @@ class ZEOOptions(Options):
transaction_timeout = None
invalidation_queue_size = None
monitor_address = None
record = None
family = None # set by -a; AF_UNIX or AF_INET
address = None # set by -a; string or (host, port)
storages = None # set by -f
_short_options = "a:C:f:hm:"
_short_options = "a:C:f:hm:r:"
_long_options = [
"address=",
"configuration=",
"filename=",
"help",
"monitor=",
"record=",
]
def handle_option(self, opt, arg):
......@@ -225,6 +228,8 @@ class ZEOOptions(Options):
key = str(1 + len(self.storages))
conf = FSConfig(key, arg)
self.storages[key] = FileStorage(conf)
elif opt in ("-r", "--record"):
self.record = arg
else:
# Pass it to the base class, for --help/-h
Options.handle_option(self, opt, arg)
......
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