[CalendarServer-changes] [13609] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Jun 5 13:05:39 PDT 2014


Revision: 13609
          http://trac.calendarserver.org//changeset/13609
Author:   sagen at apple.com
Date:     2014-06-05 13:05:39 -0700 (Thu, 05 Jun 2014)
Log Message:
-----------
Adds dashboard support for directory service stats

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/dashboard_service.py
    CalendarServer/trunk/calendarserver/tools/dashboard.py
    CalendarServer/trunk/txdav/dps/client.py
    CalendarServer/trunk/txdav/dps/commands.py
    CalendarServer/trunk/txdav/dps/server.py
    CalendarServer/trunk/txdav/who/augment.py
    CalendarServer/trunk/txdav/who/directory.py

Modified: CalendarServer/trunk/calendarserver/dashboard_service.py
===================================================================
--- CalendarServer/trunk/calendarserver/dashboard_service.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/calendarserver/dashboard_service.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -28,6 +28,7 @@
 a server admin or developer would like to keep an eye on.
 """
 
+
 class DashboardProtocol (LineReceiver):
     """
     A protocol that receives a line containing a JSON object representing a request,
@@ -153,7 +154,21 @@
         return succeed({"workers": loads, "level": level})
 
 
+    def data_directory(self):
+        """
+        Return a summary of directory service calls.
 
+        @return: the JSON result.
+        @rtype: L{str}
+        """
+        directory = self.factory.store.directoryService()
+        if hasattr(directory, "stats"):
+            return succeed(directory.stats())
+        else:
+            return succeed({})
+
+
+
 class DashboardServer(Factory):
 
     protocol = DashboardProtocol

Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/dashboard.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -738,10 +738,12 @@
 
         s = " {:<12}{:>8}{:>16}".format(
             "Total:",
-            sum([
-                record["unacknowledged"] + record["acknowledged"]
-                for record in records
-            ]),
+            sum(
+                [
+                    record["unacknowledged"] + record["acknowledged"]
+                    for record in records
+                ]
+            ),
             sum([record["total"] for record in records]),
         )
         if self.usesCurses:
@@ -919,11 +921,103 @@
         self.lastResult = records
 
 
+class DirectoryStatsWindow(BaseWindow):
+    """
+    Displays the status of the server's directory service calls
+    """
+
+    help = "display directory service stats"
+    clientItem = "directory"
+    FORMAT_WIDTH = 89
+
+
+    def makeWindow(self, top=0, left=0):
+        nlines = len(defaultIfNone(self.readItem("directory"), {}))
+        self.rowCount = nlines
+        self._createWindow(
+            "Directory Service", self.rowCount + 6, ncols=self.FORMAT_WIDTH,
+            begin_y=top, begin_x=left
+        )
+        return self
+
+
+    def update(self):
+        records = defaultIfNone(self.clientData(), {})
+        if len(records) != self.rowCount:
+            self.needsReset = True
+            return
+
+        self.iter += 1
+
+        if self.usesCurses:
+            self.window.erase()
+            self.window.border()
+            self.window.addstr(0, 2, self.title + " {} ({})".format(len(records), self.iter,))
+
+        x = 1
+        y = 1
+        s1 = " {:<40}{:>15}{:>15}{:>15} ".format(
+            "Method", "Calls", "Total", "Average"
+        )
+        s2 = " {:<40}{:>15}{:>15}{:>15} ".format(
+            "", "", "(sec)", "(sec)"
+        )
+        if self.usesCurses:
+            self.window.addstr(y, x, s1, curses.A_REVERSE)
+            self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
+        else:
+            print(s1)
+            print(s2)
+        y += 2
+
+        overallCount = 0
+        overallTimeSpent = 0.0
+
+        for methodName, (count, timeSpent) in sorted(records.items(), key=lambda x: x[0]):
+            overallCount += count
+            overallTimeSpent += timeSpent
+
+            s = " {:<40}{:>15d}{:>15.1f}{:>15.5f} ".format(
+                methodName,
+                count,
+                timeSpent,
+                timeSpent / count,
+            )
+            try:
+                if self.usesCurses:
+                    self.window.addstr(y, x, s)
+                else:
+                    print(s)
+            except curses.error:
+                pass
+            y += 1
+
+
+        s = " {:<40}{:>15d}{:>15.1f}{:>15.5f} ".format(
+            "Total:",
+            overallCount,
+            overallTimeSpent,
+            safeDivision(overallTimeSpent, overallCount, 1.0)
+        )
+        if self.usesCurses:
+            self.window.hline(y, x, "-", self.FORMAT_WIDTH - 2)
+            y += 1
+            self.window.addstr(y, x, s)
+        else:
+            print(s)
+        y += 1
+
+        if self.usesCurses:
+            self.window.refresh()
+
+
+
 Dashboard.registerWindow(SystemWindow, "s")
 Dashboard.registerWindow(RequestStatsWindow, "r")
 Dashboard.registerWindow(JobsWindow, "j")
 Dashboard.registerWindow(AssignmentsWindow, "w")
 Dashboard.registerWindow(HTTPSlotsWindow, "c")
+Dashboard.registerWindow(DirectoryStatsWindow, "d")
 Dashboard.registerWindow(HelpWindow, "h")
 
 

Modified: CalendarServer/trunk/txdav/dps/client.py
===================================================================
--- CalendarServer/trunk/txdav/dps/client.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/client.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -39,7 +39,7 @@
     RecordsMatchingTokensCommand, RecordsMatchingFieldsCommand,
     MembersCommand, GroupsCommand, SetMembersCommand,
     VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
-    WikiAccessForUID, ContinuationCommand
+    WikiAccessForUIDCommand, ContinuationCommand
 )
 from txdav.who.directory import (
     CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
@@ -401,7 +401,7 @@
     def accessForRecord(self, record):
         log.debug("DPS Client accessForRecord")
         return self.service._call(
-            WikiAccessForUID,
+            WikiAccessForUIDCommand,
             self._convertAccess,
             wikiUID=self.uid.encode("utf-8"),
             uid=record.uid.encode("utf-8")

Modified: CalendarServer/trunk/txdav/dps/commands.py
===================================================================
--- CalendarServer/trunk/txdav/dps/commands.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/commands.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -191,7 +191,7 @@
 
 
 
-class WikiAccessForUID(amp.Command):
+class WikiAccessForUIDCommand(amp.Command):
     arguments = [
         ('wikiUID', amp.String()),
         ('uid', amp.String()),

Modified: CalendarServer/trunk/txdav/dps/server.py
===================================================================
--- CalendarServer/trunk/txdav/dps/server.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/dps/server.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -36,7 +36,7 @@
     RecordsMatchingTokensCommand, RecordsMatchingFieldsCommand,
     MembersCommand, GroupsCommand, SetMembersCommand,
     VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
-    WikiAccessForUID, ContinuationCommand
+    WikiAccessForUIDCommand, ContinuationCommand
     # UpdateRecordsCommand, RemoveRecordsCommand
 )
 from txdav.who.util import directoryFromConfig
@@ -430,7 +430,7 @@
         returnValue(response)
 
 
-    @WikiAccessForUID.responder
+    @WikiAccessForUIDCommand.responder
     @inlineCallbacks
     def wikiAccessForUID(self, wikiUID, uid):
         wikiUID = wikiUID.decode("utf-8")

Modified: CalendarServer/trunk/txdav/who/augment.py
===================================================================
--- CalendarServer/trunk/txdav/who/augment.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/who/augment.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -23,6 +23,8 @@
     "AugmentedDirectoryService",
 ]
 
+import time
+
 from zope.interface import implementer
 
 from twisted.internet.defer import inlineCallbacks, returnValue
@@ -47,6 +49,47 @@
 
 
 
+def timed(f):
+    """
+    A decorator which keeps track of the wrapped function's call count and
+    total duration
+    """
+
+    def recordTiming(result, key, startTime):
+        """
+        Figures out how much time to add to the total time spent within the
+        method identified by key and stores that in the timings dict.
+
+        @param result: the result of the wrapped method
+        @param timings: the dictionary to store timings in
+        @type timings: C{dict}
+        @param key: the method name
+        @type key: C{str}
+        @param startTime: the start time of the call in seconds
+        @type startTime: C{float}
+        """
+        timings = AugmentedDirectoryService._timings
+        if key not in timings:
+            timings[key] = (0, 0.0)
+        count, timeSpent = timings[key]
+        count += 1
+        duration = (time.time() - startTime)
+        timeSpent += duration
+        timings[key] = (count, timeSpent)
+        return result
+
+
+    def timingWrapper(self, *args, **kwds):
+        """
+        Records the start time of the call and the method's name
+        """
+        d = f(self, *args, **kwds)
+        d.addBoth(recordTiming, f.func_name, time.time())
+        return d
+
+    return timingWrapper
+
+
 @implementer(IDirectoryService, IStoreDirectoryService)
 class AugmentedDirectoryService(
     BaseDirectoryService, CalendarDirectoryServiceMixin
@@ -63,7 +106,9 @@
         FieldName,
     ))
 
+    _timings = {}
 
+
     def __init__(self, directory, store, augmentDB):
         BaseDirectoryService.__init__(self, directory.realmName)
         self._directory = directory
@@ -71,6 +116,10 @@
         self._augmentDB = augmentDB
 
 
+    def stats(self):
+        return self._timings
+
+
     @property
     def recordType(self):
         # Defer to the directory service we're augmenting
@@ -104,6 +153,7 @@
         returnValue(augmented)
 
 
+    @timed
     @inlineCallbacks
     def recordWithUID(self, uid):
         # MOVE2WHO, REMOVE THIS:
@@ -116,6 +166,7 @@
         returnValue(record)
 
 
+    @timed
     @inlineCallbacks
     def recordWithGUID(self, guid):
         record = yield self._directory.recordWithGUID(guid)
@@ -123,6 +174,7 @@
         returnValue(record)
 
 
+    @timed
     @inlineCallbacks
     def recordsWithRecordType(self, recordType):
         records = yield self._directory.recordsWithRecordType(recordType)
@@ -133,6 +185,7 @@
         returnValue(augmented)
 
 
+    @timed
     @inlineCallbacks
     def recordWithShortName(self, recordType, shortName):
         # MOVE2WHO, REMOVE THIS:
@@ -147,6 +200,7 @@
         returnValue(record)
 
 
+    @timed
     @inlineCallbacks
     def recordsWithEmailAddress(self, emailAddress):
         # MOVE2WHO, REMOVE THIS:
@@ -162,6 +216,28 @@
         returnValue(augmented)
 
 
+    @timed
+    def recordWithCalendarUserAddress(self, *args, **kwds):
+        return CalendarDirectoryServiceMixin.recordWithCalendarUserAddress(
+            self, *args, **kwds
+        )
+
+
+    @timed
+    def recordsMatchingTokens(self, *args, **kwds):
+        return CalendarDirectoryServiceMixin.recordsMatchingTokens(
+            self, *args, **kwds
+        )
+
+
+    @timed
+    def recordsMatchingFields(self, *args, **kwds):
+        return CalendarDirectoryServiceMixin.recordsMatchingFields(
+            self, *args, **kwds
+        )
+
+
+    @timed
     @inlineCallbacks
     def updateRecords(self, records, create=False):
         """
@@ -364,6 +440,7 @@
         self._baseRecord = baseRecord
 
 
+    @timed
     @inlineCallbacks
     def members(self):
         augmented = []
@@ -375,6 +452,7 @@
         returnValue(augmented)
 
 
+    @timed
     @inlineCallbacks
     def groups(self):
         augmented = []
@@ -397,13 +475,16 @@
         returnValue(augmented)
 
 
+    @timed
     def verifyPlaintextPassword(self, password):
         return self._baseRecord.verifyPlaintextPassword(password)
 
 
+    @timed
     def verifyHTTPDigest(self, *args):
         return self._baseRecord.verifyHTTPDigest(*args)
 
 
+    @timed
     def accessForRecord(self, record):
         return self._baseRecord.accessForRecord(record)

Modified: CalendarServer/trunk/txdav/who/directory.py
===================================================================
--- CalendarServer/trunk/txdav/who/directory.py	2014-06-04 22:51:50 UTC (rev 13608)
+++ CalendarServer/trunk/txdav/who/directory.py	2014-06-05 20:05:39 UTC (rev 13609)
@@ -459,7 +459,7 @@
                     return candidate
 
         # fall back to using the first one
-        return sortedCuas[0] if sortedCuas else None # groups may not have cua
+        return sortedCuas[0] if sortedCuas else None  # groups may not have cua
 
 
     def enabledAsOrganizer(self):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140605/56138d98/attachment-0001.html>


More information about the calendarserver-changes mailing list