Commit 435fda11 authored by Sidnei da Silva's avatar Sidnei da Silva

parent 6c34d46f
...@@ -28,17 +28,6 @@ Zope Changes ...@@ -28,17 +28,6 @@ Zope Changes
Features added Features added
- Applied patch for
http://www.zope.org/Collectors/Zope/1527. The patch
installs a windows "control handler". Ctrl+C/Break etc are
delivered asynchronously (notwithstanding the GIL) to a new
thread. This new thread triggers a shutdown, then tricks
asyncore into breaking out of its 'select' call.
- The ZEO server now records its PID to a file like the ZEO
client. Defaults to $INSTANCE_HOME/var/ZEO.pid, and its
configurable in $INSTANCE_HOME/etc/zeo.conf.
- PluginIndexes: the ZCatalog's "Indexes" tab now show the number of - PluginIndexes: the ZCatalog's "Indexes" tab now show the number of
distinct values indexed by each index instead of a mixture of indexed distinct values indexed by each index instead of a mixture of indexed
objects versus number of distinct values. Indexes derived from UnIndex objects versus number of distinct values. Indexes derived from UnIndex
......
...@@ -38,68 +38,6 @@ def shutdown(exit_code,fast = 0): ...@@ -38,68 +38,6 @@ def shutdown(exit_code,fast = 0):
# enough, but still clean. # enough, but still clean.
_shutdown_timeout = 1.0 _shutdown_timeout = 1.0
def setup_windows_control_handler():
try:
from win32api import SetConsoleCtrlHandler, \
GenerateConsoleCtrlEvent
from win32con import CTRL_C_EVENT, CTRL_BREAK_EVENT, \
CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, \
CTRL_SHUTDOWN_EVENT
except ImportError:
pass
else:
def interrupt_select():
"""Interrupt a sleeping acyncore 'select' call"""
# What is the right thing to do here?
# asyncore.close_all() works, but I fear that would
# prevent the poll based graceful cleanup code from working.
# This seems to work :)
for fd, obj in asyncore.socket_map.items():
if hasattr(obj, "pull_trigger"):
obj.pull_trigger()
def ctrl_handler(ctrlType):
"""Called by Windows on a new thread whenever a
console control event is raised."""
result = 0
if ctrlType == CTRL_C_EVENT:
# user pressed Ctrl+C or someone did
# GenerateConsoleCtrlEvent
if _shutdown_phase == 0:
print "Shutting down Zope..."
shutdown(0)
interrupt_select()
elif _shutdown_timeout > 1.0:
print "Zope shutdown switching to 'fast'"
shutdown(0, 1)
else:
# Third time around - terminate via
# a CTRL_BREAK_EVENT
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0)
result = 1
elif ctrlType == CTRL_BREAK_EVENT:
# Always let Ctrl+Break force it down.
# Default handler terminates process.
print "Terminating Zope (press Ctrl+C to shutdown cleanly)"
elif ctrlType == CTRL_CLOSE_EVENT:
# Console is about to die.
# CTRL_CLOSE_EVENT gives us 5 seconds before displaying
# the "End process" dialog - so switch directly to 'fast'
shutdown(0, 1)
interrupt_select()
result = 1
elif ctrlType in (CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT):
# MSDN says:
# "Note that this signal is received only by services.
# Interactive applications are terminated at logoff, so
# they are not present when the system sends this signal."
# We can therefore ignore it (our service framework
# manages shutdown in this case)
pass
return result
# Install our handler.
SetConsoleCtrlHandler(ctrl_handler)
def loop(): def loop():
# Run the main loop until someone calls shutdown() # Run the main loop until someone calls shutdown()
lifetime_loop() lifetime_loop()
...@@ -108,9 +46,6 @@ def loop(): ...@@ -108,9 +46,6 @@ def loop():
graceful_shutdown_loop() graceful_shutdown_loop()
def lifetime_loop(): def lifetime_loop():
if sys.platform.startswith("win"):
setup_windows_control_handler()
# The main loop. Stay in here until we need to shutdown # The main loop. Stay in here until we need to shutdown
map = asyncore.socket_map map = asyncore.socket_map
timeout = 30.0 timeout = 30.0
......
...@@ -93,15 +93,6 @@ ...@@ -93,15 +93,6 @@
</description> </description>
</key> </key>
<key name="pid-filename" datatype="existing-dirpath"
required="no">
<description>
The full path to the file in which to write the ZEO server's Process ID
at startup. If omitted, $INSTANCE/var/ZEO.pid is used.
</description>
<metadefault>$INSTANCE/var/ZEO.pid (or $clienthome/ZEO.pid)</metadefault>
</key>
</sectiontype> </sectiontype>
</component> </component>
...@@ -47,7 +47,6 @@ zeo_conf_template = """\ ...@@ -47,7 +47,6 @@ zeo_conf_template = """\
address %(port)d address %(port)d
read-only false read-only false
invalidation-queue-size 100 invalidation-queue-size 100
# pid-filename $INSTANCE/var/ZEO.pid
# monitor-address PORT # monitor-address PORT
# transaction-timeout SECONDS # transaction-timeout SECONDS
</zeo> </zeo>
......
...@@ -104,8 +104,6 @@ class ZEOOptionsMixin: ...@@ -104,8 +104,6 @@ class ZEOOptionsMixin:
None, 'auth-database=') None, 'auth-database=')
self.add('auth_realm', 'zeo.authentication_realm', self.add('auth_realm', 'zeo.authentication_realm',
None, 'auth-realm=') None, 'auth-realm=')
self.add('pid_file', 'zeo.pid_filename',
None, 'pid-file=')
class ZEOOptions(ZDOptions, ZEOOptionsMixin): class ZEOOptions(ZDOptions, ZEOOptionsMixin):
...@@ -128,7 +126,6 @@ class ZEOServer: ...@@ -128,7 +126,6 @@ class ZEOServer:
self.setup_default_logging() self.setup_default_logging()
self.check_socket() self.check_socket()
self.clear_socket() self.clear_socket()
self.make_pidfile()
try: try:
self.open_storages() self.open_storages()
self.setup_signals() self.setup_signals()
...@@ -137,7 +134,6 @@ class ZEOServer: ...@@ -137,7 +134,6 @@ class ZEOServer:
finally: finally:
self.close_storages() self.close_storages()
self.clear_socket() self.clear_socket()
self.remove_pidfile()
def setup_default_logging(self): def setup_default_logging(self):
if self.options.config_logger is not None: if self.options.config_logger is not None:
...@@ -186,8 +182,6 @@ class ZEOServer: ...@@ -186,8 +182,6 @@ class ZEOServer:
method is called without additional arguments. method is called without additional arguments.
""" """
if os.name != "posix": if os.name != "posix":
if os.name == "nt":
self.setup_win32_signals()
return return
if hasattr(signal, 'SIGXFSZ'): if hasattr(signal, 'SIGXFSZ'):
signal.signal(signal.SIGXFSZ, signal.SIG_IGN) # Special case signal.signal(signal.SIGXFSZ, signal.SIG_IGN) # Special case
...@@ -199,48 +193,6 @@ class ZEOServer: ...@@ -199,48 +193,6 @@ class ZEOServer:
method() method()
signal.signal(sig, wrapper) signal.signal(sig, wrapper)
def setup_win32_signals(self):
try:
from win32api import SetConsoleCtrlHandler
import win32con # our handler uses this
except ImportError:
warn("no pywin32 extensions - can't install ctrl+c handler")
else:
SetConsoleCtrlHandler(self._win32_ctrl_handler)
# And borrow the Zope Signals module to get a log reopen handler.
from Signals.WinSignalHandler import SignalHandler
from Signals.Signals import logfileReopenHandler
SIGUSR2 = 12
SignalHandler.registerHandler(SIGUSR2, logfileReopenHandler)
def _win32_ctrl_handler(self, ctrlType):
"""Called by Windows on a new thread whenever a
console control event is raised."""
from win32con import CTRL_C_EVENT, CTRL_BREAK_EVENT, \
CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, \
CTRL_SHUTDOWN_EVENT
import asyncore
result = 0
# Note we probably don't want to raise SystemExit from
# this thread - pywin32-203 at least calls PyErr_Print,
# which will still terminate us (but print a message
# about the callback failing)
if ctrlType == CTRL_C_EVENT:
# user pressed Ctrl+C or someone did
# GenerateConsoleCtrlEvent
info("terminated by CTRL_C_EVENT")
asyncore.close_all()
# Default will raise KeyboardInterrupt - we don't need that
elif ctrlType == CTRL_BREAK_EVENT:
info("terminated by CTRL_BREAK_EVENT")
asyncore.close_all()
# Default handler terminates process - result remains 0
elif ctrlType == CTRL_CLOSE_EVENT:
info("terminated by CTRL_CLOSE_EVENT")
asyncore.close_all()
result = 1
return result
def create_server(self): def create_server(self):
from ZEO.StorageServer import StorageServer from ZEO.StorageServer import StorageServer
self.server = StorageServer( self.server = StorageServer(
...@@ -276,37 +228,6 @@ class ZEOServer: ...@@ -276,37 +228,6 @@ class ZEOServer:
# Should we restart as with SIGHUP? # Should we restart as with SIGHUP?
log("received SIGUSR2, but it was not handled!", level=logging.WARNING) log("received SIGUSR2, but it was not handled!", level=logging.WARNING)
def make_pidfile(self):
if not self.options.read_only:
pidfile = self.options.pid_file
# 'pidfile' is marked as not required.
if not pidfile:
pidfile = os.path.join(os.environ["INSTANCE_HOME"],
"var", "ZEO.pid")
try:
if os.path.exists(pidfile):
os.unlink(pidfile)
pid = os.getpid()
f = open(pidfile,'w')
f.write(`pid`)
f.close()
except IOError:
error("PID file '%s' cannot be opened.")
except AttributeError:
pass # getpid not supported. Unix/Win only
def remove_pidfile(self):
if not self.options.read_only:
pidfile = self.options.pid_file
if not pidfile:
pidfile = os.path.join(os.environ["INSTANCE_HOME"],
"var", "ZEO.pid")
try:
if os.path.exists(pidfile):
os.unlink(pidfile)
except IOError:
error("PID file '%s' could not be removed.")
def close_storages(self): def close_storages(self):
for name, storage in self.storages.items(): for name, storage in self.storages.items():
log("closing storage %r" % name) log("closing storage %r" % name)
......
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