[CalendarServer-changes] [9249] CalendarServer/trunk/twext
source_changes at macosforge.org
source_changes at macosforge.org
Wed May 16 07:35:03 PDT 2012
Revision: 9249
http://trac.macosforge.org/projects/calendarserver/changeset/9249
Author: cdaboo at apple.com
Date: 2012-05-16 07:35:02 -0700 (Wed, 16 May 2012)
Log Message:
-----------
Handle issues with incorrect tracking of busy status of child processes.
Modified Paths:
--------------
CalendarServer/trunk/twext/internet/sendfdport.py
CalendarServer/trunk/twext/internet/test/test_sendfdport.py
CalendarServer/trunk/twext/web2/metafd.py
CalendarServer/trunk/twext/web2/test/test_metafd.py
Modified: CalendarServer/trunk/twext/internet/sendfdport.py
===================================================================
--- CalendarServer/trunk/twext/internet/sendfdport.py 2012-05-15 15:38:47 UTC (rev 9248)
+++ CalendarServer/trunk/twext/internet/sendfdport.py 2012-05-16 14:35:02 UTC (rev 9249)
@@ -122,7 +122,7 @@
Receive a status / health message and record it.
"""
try:
- data, flags, ancillary = recvmsg(self.skt.fileno())
+ data, _ignore_flags, _ignore_ancillary = recvmsg(self.skt.fileno())
except SocketError, se:
if se.errno not in (EAGAIN, ENOBUFS):
raise
@@ -192,7 +192,11 @@
@param description: some text to identify to the subprocess's
L{InheritedPort} what type of transport to create for this socket.
"""
- self._subprocessSockets.sort(key=lambda conn: conn.status)
+
+ # We want None to sort after 0 and before 1, so coerce to 0.5 - this allows the master
+ # to first schedule all child process that are up but not yet busy ahead of those that
+ # are still starting up.
+ self._subprocessSockets.sort(key=lambda conn: 0.5 if conn.status is None else conn.status)
selectedSocket = self._subprocessSockets[0]
selectedSocket.sendSocketToPeer(skt, description)
# XXX Maybe want to send along 'description' or 'skt' or some
Modified: CalendarServer/trunk/twext/internet/test/test_sendfdport.py
===================================================================
--- CalendarServer/trunk/twext/internet/test/test_sendfdport.py 2012-05-15 15:38:47 UTC (rev 9248)
+++ CalendarServer/trunk/twext/internet/test/test_sendfdport.py 2012-05-16 14:35:02 UTC (rev 9249)
@@ -1,6 +1,6 @@
# -*- test-case-name: twext.internet.test.test_sendfdport -*-
##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
+# Copyright (c) 2010-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,9 +19,11 @@
Tests for L{twext.internet.sendfdport}.
"""
+from twext.internet.sendfdport import InheritedSocketDispatcher,\
+ _SubprocessSocket
+from twext.web2.metafd import ConnectionLimiter
+from twisted.internet.interfaces import IReactorFDSet
from twisted.trial.unittest import TestCase
-from twext.internet.sendfdport import InheritedSocketDispatcher
-from twisted.internet.interfaces import IReactorFDSet
from zope.interface.declarations import implements
@@ -55,3 +57,54 @@
dispatcher.startDispatching()
dispatcher.addSocket()
self.assertEquals(reactor.getReaders(), dispatcher._subprocessSockets)
+
+
+ def test_sendFileDescriptorSorting(self):
+ """
+ Make sure InheritedSocketDispatcher.sendFileDescriptor sorts sockets with status None
+ higher than those with int status values.
+ """
+
+ self.patch(_SubprocessSocket, 'sendSocketToPeer', lambda x, y, z:None)
+ dispatcher = InheritedSocketDispatcher(ConnectionLimiter(2, 20))
+ dispatcher.addSocket()
+ dispatcher.addSocket()
+ dispatcher.addSocket()
+
+ sockets = dispatcher._subprocessSockets[:]
+
+ # Check that 0 is preferred over None
+ sockets[0].status = 0
+ sockets[1].status = 1
+ sockets[2].status = None
+
+ dispatcher.sendFileDescriptor(None, "")
+
+ self.assertEqual(sockets[0].status, 1)
+ self.assertEqual(sockets[1].status, 1)
+ self.assertEqual(sockets[2].status, None)
+
+ dispatcher.sendFileDescriptor(None, "")
+
+ self.assertEqual(sockets[0].status, 1)
+ self.assertEqual(sockets[1].status, 1)
+ self.assertEqual(sockets[2].status, 1)
+
+ # Check that after going to 1 and back to 0 that is still preferred over None
+ sockets[0].status = 0
+ sockets[1].status = 1
+ sockets[2].status = None
+
+ dispatcher.sendFileDescriptor(None, "")
+
+ self.assertEqual(sockets[0].status, 1)
+ self.assertEqual(sockets[1].status, 1)
+ self.assertEqual(sockets[2].status, None)
+
+ sockets[1].status = 0
+
+ dispatcher.sendFileDescriptor(None, "")
+
+ self.assertEqual(sockets[0].status, 1)
+ self.assertEqual(sockets[1].status, 1)
+ self.assertEqual(sockets[2].status, None)
Modified: CalendarServer/trunk/twext/web2/metafd.py
===================================================================
--- CalendarServer/trunk/twext/web2/metafd.py 2012-05-15 15:38:47 UTC (rev 9248)
+++ CalendarServer/trunk/twext/web2/metafd.py 2012-05-16 14:35:02 UTC (rev 9249)
@@ -15,20 +15,19 @@
# limitations under the License.
##
-from twisted.internet.tcp import Server
+from twext.internet.sendfdport import (
+ InheritedPort, InheritedSocketDispatcher, InheritingProtocolFactory)
from twext.internet.tcp import MaxAcceptTCPServer
-
+from twext.python.log import Logger
+from twext.web2.channel.http import HTTPFactory
+from twisted.application.service import MultiService, Service
from twisted.internet import reactor
+from twisted.internet.tcp import Server
-from twisted.application.service import MultiService, Service
+log = Logger()
-from twext.web2.channel.http import HTTPFactory
-from twext.internet.sendfdport import (
- InheritedPort, InheritedSocketDispatcher, InheritingProtocolFactory)
-
-
class JustEnoughLikeAPort(object):
"""
Fake out just enough of L{tcp.Port} to be acceptable to
@@ -198,10 +197,19 @@
# accepting connections again if we paused (see
# newConnectionStatus)
result = self.intWithNoneAsZero(previousStatus) - 1
+ if result < 0:
+ log.err("metafd: trying to decrement status below zero")
+ result = 0
else:
# A new process just started accepting new connections; zero
- # out its expected load.
- result = 0
+ # out its expected load, but only if previous status is still None
+ result = 0 if previousStatus is None else previousStatus
+ if previousStatus is None:
+ result = 0
+ else:
+ log.err("metafd: trying to zero status that is not None")
+ result = previousStatus
+
# If load has indeed decreased (i.e. in any case except 'a new,
# idle process replaced an old, idle process'), then start
# listening again.
Modified: CalendarServer/trunk/twext/web2/test/test_metafd.py
===================================================================
--- CalendarServer/trunk/twext/web2/test/test_metafd.py 2012-05-15 15:38:47 UTC (rev 9248)
+++ CalendarServer/trunk/twext/web2/test/test_metafd.py 2012-05-16 14:35:02 UTC (rev 9249)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2011 Apple Inc. All rights reserved.
+# Copyright (c) 2011-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,13 +22,11 @@
from socket import error as SocketError, AF_INET
from errno import ENOTCONN
+from twext.internet import sendfdport
from twext.web2 import metafd
-from twext.web2.metafd import ReportingHTTPService
from twext.web2.channel.http import HTTPChannel
-from twext.internet import sendfdport
+from twext.web2.metafd import ReportingHTTPService, ConnectionLimiter
from twisted.internet.tcp import Server
-
-
from twisted.trial.unittest import TestCase
@@ -142,3 +140,37 @@
self.assertEqual(len(channels), 1)
self.assertEqual(list(channels)[0].transport.getPeer().host, "0.0.0.0")
+
+
+class ConnectionLimiterTests(TestCase):
+ """
+ Tests for L{ConnectionLimiter}
+ """
+
+
+ def test_statusFromMessage(self):
+ """
+ Test ConnectionLimiter.statusFromMessage to make sure count cannot go below zero and that
+ zeroing out does not wipe out an existing count.
+ """
+
+ cl = ConnectionLimiter(2, 20)
+
+ # "0" Zeroing out does not overwrite legitimate count
+ self.assertEqual(cl.statusFromMessage(None, "0"), 0)
+ self.assertEqual(cl.statusFromMessage(0, "0"), 0)
+ self.assertEqual(cl.statusFromMessage(1, "0"), 1)
+ self.assertEqual(cl.statusFromMessage(2, "0"), 2)
+
+ # "-" No negative counts
+ self.assertEqual(cl.statusFromMessage(None, "-"), 0)
+ self.assertEqual(cl.statusFromMessage(0, "-"), 0)
+ self.assertEqual(cl.statusFromMessage(1, "-"), 0)
+ self.assertEqual(cl.statusFromMessage(2, "-"), 1)
+
+ # "+" No change
+ self.assertEqual(cl.statusFromMessage(None, "+"), 0)
+ self.assertEqual(cl.statusFromMessage(0, "+"), 0)
+ self.assertEqual(cl.statusFromMessage(1, "+"), 1)
+ self.assertEqual(cl.statusFromMessage(2, "+"), 2)
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120516/13c8b2a4/attachment.html>
More information about the calendarserver-changes
mailing list