[CalendarServer-changes] [7316] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Apr 13 17:08:53 PDT 2011


Revision: 7316
          http://trac.macosforge.org/projects/calendarserver/changeset/7316
Author:   sagen at apple.com
Date:     2011-04-13 17:08:52 -0700 (Wed, 13 Apr 2011)
Log Message:
-----------
Adds call to recycleAutoreleasePool after calls to OpenDirectory.framework via PyObjC; also purges expired directory records from internal caches.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/platform/darwin/od/opendirectory.py
    CalendarServer/trunk/twistedcaldav/directory/cachingdirectory.py

Modified: CalendarServer/trunk/calendarserver/platform/darwin/od/opendirectory.py
===================================================================
--- CalendarServer/trunk/calendarserver/platform/darwin/od/opendirectory.py	2011-04-13 18:58:40 UTC (rev 7315)
+++ CalendarServer/trunk/calendarserver/platform/darwin/od/opendirectory.py	2011-04-14 00:08:52 UTC (rev 7316)
@@ -215,37 +215,41 @@
 
     attributeNames, encodings = attributeNamesFromList(attributes)
 
-    tries = NUM_TRIES
-    while tries:
-        query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
-            directory.node,
-            recordType,
-            None,
-            MATCHANY,
-            None,
-            attributeNames,
-            count,
-            None)
+    try:
+        tries = NUM_TRIES
+        while tries:
+            query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+                directory.node,
+                recordType,
+                None,
+                MATCHANY,
+                None,
+                attributeNames,
+                count,
+                None)
 
-        if not error:
-            records, error = query.resultsAllowingPartial_error_(False, None)
+            if not error:
+                records, error = query.resultsAllowingPartial_error_(False, None)
 
-        if not error:
-            for record in records:
-                results.append(recordToResult(record, encodings))
-            return results
+            if not error:
+                for record in records:
+                    results.append(recordToResult(record, encodings))
+                return results
 
-        code = error.code()
-        log.debug("Received code %d from query call: %s" % (code, error))
+            code = error.code()
+            log.debug("Received code %d from query call: %s" % (code, error))
 
-        if code in RETRY_CODES:
-            tries -= 1
-        else:
-            break
+            if code in RETRY_CODES:
+                tries -= 1
+            else:
+                break
 
-    log.error(error)
-    raise ODError(error)
+        log.error(error)
+        raise ODError(error)
 
+    finally:
+        objc.recycleAutoreleasePool()
+
 def queryRecordsWithAttribute_list(directory, attr, value, matchType, casei, recordType, attributes, count=0):
     """
     List records in Open Directory matching specified attribute/value, and return key attributes for each one.
@@ -268,39 +272,43 @@
 
     attributeNames, encodings = attributeNamesFromList(attributes)
 
-    tries = NUM_TRIES
-    while tries:
+    try:
+        tries = NUM_TRIES
+        while tries:
 
-        query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
-            directory.node,
-            recordType,
-            attr,
-            adjustMatchType(matchType, casei),
-            value.decode("utf-8"),
-            attributeNames,
-            count,
-            None)
+            query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+                directory.node,
+                recordType,
+                attr,
+                adjustMatchType(matchType, casei),
+                value.decode("utf-8"),
+                attributeNames,
+                count,
+                None)
 
-        if not error:
-            records, error = query.resultsAllowingPartial_error_(False, None)
+            if not error:
+                records, error = query.resultsAllowingPartial_error_(False, None)
 
-        if not error:
-            for record in records:
-                results.append(recordToResult(record, encodings))
-            return results
+            if not error:
+                for record in records:
+                    results.append(recordToResult(record, encodings))
+                return results
 
-        code = error.code()
-        log.debug("Received code %d from query call: %s" % (code, error))
+            code = error.code()
+            log.debug("Received code %d from query call: %s" % (code, error))
 
-        if code in RETRY_CODES:
-            tries -= 1
-        else:
-            break
+            if code in RETRY_CODES:
+                tries -= 1
+            else:
+                break
 
-    log.error(error)
-    raise ODError(error)
+        log.error(error)
+        raise ODError(error)
 
+    finally:
+        objc.recycleAutoreleasePool()
 
+
 def queryRecordsWithAttributes_list(directory, compound, casei, recordType, attributes, count=0):
     """
     List records in Open Directory matching specified criteria, and return key attributes for each one.
@@ -320,39 +328,43 @@
 
     attributeNames, encodings = attributeNamesFromList(attributes)
 
-    tries = NUM_TRIES
-    while tries:
+    try:
+        tries = NUM_TRIES
+        while tries:
 
-        query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
-            directory.node,
-            recordType,
-            None,
-            0x210B, # adjustMatchType(matchType, casei),
-            compound,
-            attributeNames,
-            count,
-            None)
+            query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+                directory.node,
+                recordType,
+                None,
+                0x210B, # adjustMatchType(matchType, casei),
+                compound,
+                attributeNames,
+                count,
+                None)
 
-        if not error:
-            records, error = query.resultsAllowingPartial_error_(False, None)
+            if not error:
+                records, error = query.resultsAllowingPartial_error_(False, None)
 
-        if not error:
-            for record in records:
-                results.append(recordToResult(record, encodings))
-            return results
+            if not error:
+                for record in records:
+                    results.append(recordToResult(record, encodings))
+                return results
 
-        code = error.code()
-        log.debug("Received code %d from query call: %s" % (code, error))
+            code = error.code()
+            log.debug("Received code %d from query call: %s" % (code, error))
 
-        if code in RETRY_CODES:
-            tries -= 1
-        else:
-            break
+            if code in RETRY_CODES:
+                tries -= 1
+            else:
+                break
 
-    log.error(error)
-    raise ODError(error)
+        log.error(error)
+        raise ODError(error)
 
+    finally:
+        objc.recycleAutoreleasePool()
 
+
 def getUserRecord(directory, user):
     """
     Look up the record for the given user within the directory's node
@@ -395,39 +407,43 @@
     @param pswd: C{str} containing the password to check.
     @return: C{True} if the user was found, C{False} otherwise.
     """
-    record = getUserRecord(directory, user)
-    if record is None:
-        raise ODError("Record not found")
+    try:
+        record = getUserRecord(directory, user)
+        if record is None:
+            raise ODError("Record not found")
 
-    tries = NUM_TRIES
-    while tries:
+        tries = NUM_TRIES
+        while tries:
 
-        log.debug("Checking basic auth for user '%s' (tries remaining: %d)" %
-            (user, tries))
+            log.debug("Checking basic auth for user '%s' (tries remaining: %d)" %
+                (user, tries))
 
-        result, error = record.verifyPassword_error_(password, None)
-        if not error:
-            log.debug("Basic auth for user '%s' result: %s" % (user, result))
-            return result
+            result, error = record.verifyPassword_error_(password, None)
+            if not error:
+                log.debug("Basic auth for user '%s' result: %s" % (user, result))
+                return result
 
-        code = error.code()
+            code = error.code()
 
-        if code == INCORRECT_CREDENTIALS:
-            log.debug("Basic auth for user '%s' failed due to incorrect credentials" % (user,))
-            return False
+            if code == INCORRECT_CREDENTIALS:
+                log.debug("Basic auth for user '%s' failed due to incorrect credentials" % (user,))
+                return False
 
-        log.debug("Basic auth for user '%s' failed with code %d (%s)" %
-            (user, code, error))
+            log.debug("Basic auth for user '%s' failed with code %d (%s)" %
+                (user, code, error))
 
-        if code in RETRY_CODES:
-            tries -= 1
-        else:
-            break
+            if code in RETRY_CODES:
+                tries -= 1
+            else:
+                break
 
-    log.error(error)
-    raise ODError(error)
+        log.error(error)
+        raise ODError(error)
 
+    finally:
+        objc.recycleAutoreleasePool()
 
+
 def authenticateUserDigest(directory, nodeName, user, challenge, response, method):
     """
     Authenticate using HTTP Digest credentials to Open Directory.
@@ -440,44 +456,48 @@
     @param method: C{str} the HTTP method being used.
     @return: C{True} if the user was found, C{False} otherwise.
     """
-    record = getUserRecord(directory, user)
-    if record is None:
-        raise ODError("Record not found")
+    try:
+        record = getUserRecord(directory, user)
+        if record is None:
+            raise ODError("Record not found")
 
-    tries = NUM_TRIES
-    while tries:
+        tries = NUM_TRIES
+        while tries:
 
-        log.debug("Checking digest auth for user '%s' (tries remaining: %d)" %
-            (user, tries))
+            log.debug("Checking digest auth for user '%s' (tries remaining: %d)" %
+                (user, tries))
 
-        # TODO: what are these other return values?
-        result, mystery1, mystery2, error = record.verifyExtendedWithAuthenticationType_authenticationItems_continueItems_context_error_(
-            DIGEST_MD5,
-            [user, challenge, response, method],
-            None, None, None
-        )
-        if not error:
-            log.debug("Digest auth for user '%s' result: %s" % (user, result))
-            return result
+            # TODO: what are these other return values?
+            result, mystery1, mystery2, error = record.verifyExtendedWithAuthenticationType_authenticationItems_continueItems_context_error_(
+                DIGEST_MD5,
+                [user, challenge, response, method],
+                None, None, None
+            )
+            if not error:
+                log.debug("Digest auth for user '%s' result: %s" % (user, result))
+                return result
 
-        code = error.code()
+            code = error.code()
 
-        if code == INCORRECT_CREDENTIALS:
-            log.debug("Digest auth for user '%s' failed due to incorrect credentials" % (user,))
-            return False
+            if code == INCORRECT_CREDENTIALS:
+                log.debug("Digest auth for user '%s' failed due to incorrect credentials" % (user,))
+                return False
 
-        log.debug("Digest auth for user '%s' failed with code %d (%s)" %
-            (user, code, error))
+            log.debug("Digest auth for user '%s' failed with code %d (%s)" %
+                (user, code, error))
 
-        if code in RETRY_CODES:
-            tries -= 1
-        else:
-            break
+            if code in RETRY_CODES:
+                tries -= 1
+            else:
+                break
 
-    log.error(error)
-    raise ODError(error)
+        log.error(error)
+        raise ODError(error)
 
+    finally:
+        objc.recycleAutoreleasePool()
 
+
 class ODError(Exception):
     """
     Exceptions from DirectoryServices errors.

Modified: CalendarServer/trunk/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/cachingdirectory.py	2011-04-13 18:58:40 UTC (rev 7315)
+++ CalendarServer/trunk/twistedcaldav/directory/cachingdirectory.py	2011-04-14 00:08:52 UTC (rev 7316)
@@ -74,6 +74,7 @@
             CachingDirectoryService.INDEX_TYPE_AUTHID   : {},
         }
         self.directoryService = directoryService
+        self.lastPurgedTime = time.time()
 
     def addRecord(self, record, indexType, indexKey, useMemcache=True,
         neverExpire=False):
@@ -121,8 +122,22 @@
                         self.log_debug("Missing record index item; type: %s, item: %s" % (indexType, item))
         
     def findRecord(self, indexType, indexKey):
+        self.purgeExpiredRecords()
         return self.recordsIndexedBy[indexType].get(indexKey)
 
+
+    def purgeExpiredRecords(self):
+        """
+        Scan the cached records and remove any that have expired.
+        Does nothing if we've scanned within the past cacheTimeout seconds.
+        """
+        if time.time() - self.lastPurgedTime > self.directoryService.cacheTimeout:
+            for record in list(self.records):
+                if record.isExpired():
+                    self.removeRecord(record)
+            self.lastPurgedTime = time.time()
+
+            
 class CachingDirectoryService(DirectoryService):
     """
     Caching Directory implementation of L{IDirectoryService}.
@@ -272,10 +287,7 @@
                 record = self.recordCacheForType(recordType).findRecord(indexType, indexKey)
 
                 if record:
-                    if (
-                        record.cachedTime != 0 and
-                        time.time() - record.cachedTime > self.cacheTimeout
-                    ):
+                    if record.isExpired():
                         self.recordCacheForType(recordType).removeRecord(record)
                         return None
                     else:
@@ -386,6 +398,20 @@
     def neverExpire(self):
         self.cachedTime = 0
 
+    def isExpired(self):
+        """
+        Returns True if this record was created more than cacheTimeout
+        seconds ago
+        """
+        if (
+            self.cachedTime != 0 and
+            time.time() - self.cachedTime > self.service.cacheTimeout
+        ):
+            return True
+        else:
+            return False
+
+
 class DirectoryMemcacheError(DirectoryError):
     """
     Error communicating with memcached.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110413/2de65bbe/attachment-0001.html>


More information about the calendarserver-changes mailing list