[CalendarServer-changes] [9721] CalendarServer/trunk/twistedcaldav/directory
source_changes at macosforge.org
source_changes at macosforge.org
Thu Aug 16 18:54:54 PDT 2012
Revision: 9721
http://trac.macosforge.org/projects/calendarserver/changeset/9721
Author: sagen at apple.com
Date: 2012-08-16 18:54:53 -0700 (Thu, 16 Aug 2012)
Log Message:
-----------
Have GroupCacher update the cache token for principals whose group membership changes so the PROPFIND response cache is invalidated
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/directory/aggregate.py
CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
CalendarServer/trunk/twistedcaldav/directory/directory.py
CalendarServer/trunk/twistedcaldav/directory/idirectory.py
CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py
CalendarServer/trunk/twistedcaldav/directory/principal.py
CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py
CalendarServer/trunk/twistedcaldav/directory/test/test_livedirectory.py
Modified: CalendarServer/trunk/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/aggregate.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/aggregate.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -148,6 +148,18 @@
def recordWithCalendarUserAddress(self, address):
return self._queryAll("recordWithCalendarUserAddress", address)
+ def recordWithCachedGroupsAlias(self, recordType, alias):
+ """
+ @param recordType: the type of the record to look up.
+ @param alias: the cached-groups alias of the record to look up.
+ @type alias: C{str}
+
+ @return: a deferred L{IDirectoryRecord} with the given cached-groups
+ alias, or C{None} if no such record is found.
+ """
+ service = self.serviceForRecordType(recordType)
+ return service.recordWithCachedGroupsAlias(recordType, alias)
+
@inlineCallbacks
def recordsMatchingFields(self, fields, operand="or", recordType=None):
Modified: CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -381,7 +381,7 @@
guids = set()
- self.log_info("Looking up which groups %s is a member of" % (guid,))
+ self.log_debug("Looking up which groups %s is a member of" % (guid,))
try:
self.log_debug("opendirectory.queryRecordsWithAttribute_list(%r,%r,%r,%r,%r,%r,%r)" % (
self.directory,
@@ -442,7 +442,7 @@
if recordGUID:
guids.add(recordGUID)
- self.log_info("%s is a member of %d groups" % (guid, len(guids)))
+ self.log_debug("%s is a member of %d groups" % (guid, len(guids)))
return guids
@@ -1235,7 +1235,7 @@
loop = 1
while valuesToFetch:
- self.log_info("getGroups loop %d" % (loop,))
+ self.log_debug("getGroups loop %d" % (loop,))
results = []
@@ -1243,12 +1243,12 @@
fields = []
for value in batch:
fields.append(["guid", value, False, "equals"])
- self.log_info("getGroups fetching batch of %d" %
+ self.log_debug("getGroups fetching batch of %d" %
(len(fields),))
result = list((yield self.recordsMatchingFields(fields,
recordType=self.recordType_groups)))
results.extend(result)
- self.log_info("getGroups got back batch of %d for subtotal of %d" %
+ self.log_debug("getGroups got back batch of %d for subtotal of %d" %
(len(result), len(results)))
# Reset values for next iteration
@@ -1262,7 +1262,7 @@
# record.nestedGUIDs() contains the sub groups of this group
for memberGUID in record.nestedGUIDs():
if memberGUID not in recordsByGUID:
- self.log_info("getGroups group %s contains group %s" %
+ self.log_debug("getGroups group %s contains group %s" %
(record.guid, memberGUID))
valuesToFetch.add(memberGUID)
Modified: CalendarServer/trunk/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/directory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/directory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -213,6 +213,18 @@
return record if record and record.enabledForCalendaring else None
+ def recordWithCachedGroupsAlias(self, recordType, alias):
+ """
+ @param recordType: the type of the record to look up.
+ @param alias: the cached-groups alias of the record to look up.
+ @type alias: C{str}
+
+ @return: a deferred L{IDirectoryRecord} with the given cached-groups
+ alias, or C{None} if no such record is found.
+ """
+ # The default implementation uses guid
+ return succeed(self.recordWithGUID(alias))
+
def allRecords(self):
for recordType in self.recordTypes():
for record in self.listRecords(recordType):
@@ -787,13 +799,6 @@
for member in groupMembers:
memberships = members.setdefault(member, set())
memberships.add(groupGUID)
- if member in previousMembers:
- # Remove from previousMembers; anything still left in
- # previousMembers when this loop is done will be
- # deleted from cache (since only members that were
- # previously in delegated-to groups but are no longer
- # would still be in previousMembers)
- del previousMembers[member]
self.log_info("There are %d users delegated-to via groups" %
(len(members),))
@@ -813,15 +818,43 @@
self.log_info("Storing %d group memberships in memcached" %
(len(members),))
+ changedMembers = set()
for member, groups in members.iteritems():
# self.log_debug("%s is in %s" % (member, groups))
yield self.cache.setGroupsFor(member, groups)
+ if groups != previousMembers.get(member, None):
+ # This principal has had a change in group membership
+ # so invalidate the PROPFIND response cache
+ changedMembers.add(member)
+ try:
+ # Remove from previousMembers; anything still left in
+ # previousMembers when this loop is done will be
+ # deleted from cache (since only members that were
+ # previously in delegated-to groups but are no longer
+ # would still be in previousMembers)
+ del previousMembers[member]
+ except KeyError:
+ pass
# Remove entries for principals that no longer are in delegated-to
# groups
for member, groups in previousMembers.iteritems():
yield self.cache.deleteGroupsFor(member)
+ changedMembers.add(member)
+ # For principals whose group membership has changed, call groupsChanged()
+ if not fast and hasattr(self.directory, "principalCollection"):
+ for member in changedMembers:
+ record = yield self.directory.recordWithCachedGroupsAlias(
+ self.directory.recordType_users, member)
+ if record is not None:
+ principal = self.directory.principalCollection.principalForRecord(record)
+ if principal is not None:
+ self.log_debug("Group membership changed for %s (%s)" %
+ (record.shortNames[0], record.guid,))
+ if hasattr(principal, "groupsChanged"):
+ yield principal.groupsChanged()
+
yield self.cache.setPopulatedMarker()
if useLock:
@@ -1033,6 +1066,14 @@
from calendarserver.tap.util import directoryFromConfig
directory = directoryFromConfig(config)
+ # We have to set cacheNotifierFactory otherwise group cacher can't
+ # invalidate the cache tokens for principals whose membership has
+ # changed
+ if config.EnableResponseCache and config.Memcached.Pools.Default.ClientEnabled:
+ from twistedcaldav.directory.principal import DirectoryPrincipalResource
+ from twistedcaldav.cache import MemcacheChangeNotifier
+ DirectoryPrincipalResource.cacheNotifierFactory = MemcacheChangeNotifier
+
# Setup the ProxyDB Service
proxydbClass = namedClass(config.ProxyDBService.type)
Modified: CalendarServer/trunk/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/idirectory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/idirectory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -81,6 +81,17 @@
directory service may not be aware of these addresses.
"""
+ def recordWithCachedGroupsAlias(recordType, alias):
+ """
+ @param recordType: the type of the record to look up.
+ @param alias: the cached-groups alias of the record to look up.
+ @type alias: C{str}
+
+ @return: a deferred L{IDirectoryRecord} with the given cached-groups
+ alias, or C{None} if no such record is found.
+ """
+
+
def recordsMatchingFields(fields):
"""
@return: a deferred sequence of L{IDirectoryRecord}s which
Modified: CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/ldapdirectory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -246,6 +246,9 @@
# Also put the guidAttr attribute into the mappings for each type
# so recordsMatchingFields can query on guid
self.rdnSchema[recordType]["mapping"]["guid"] = self.rdnSchema["guidAttr"]
+ # Also put the memberIdAttr attribute into the mappings for each type
+ # so recordsMatchingFields can query on memberIdAttr
+ self.rdnSchema[recordType]["mapping"]["memberIdAttr"] = self.groupSchema["memberIdAttr"]
if self.groupSchema["membersAttr"]:
attrSet.add(self.groupSchema["membersAttr"])
if self.groupSchema["nestedGroupsAttr"]:
@@ -346,6 +349,26 @@
return records
+ @inlineCallbacks
+ def recordWithCachedGroupsAlias(self, recordType, alias):
+ """
+ @param recordType: the type of the record to look up.
+ @param alias: the cached-groups alias of the record to look up.
+ @type alias: C{str}
+
+ @return: a deferred L{IDirectoryRecord} with the given cached-groups
+ alias, or C{None} if no such record is found.
+ """
+ memberIdAttr = self.groupSchema["memberIdAttr"]
+ attributeToSearch = "memberIdAttr" if memberIdAttr else "dn"
+
+ fields = [[attributeToSearch, alias, False, "equals"]]
+ results = (yield self.recordsMatchingFields(fields, recordType=recordType))
+ if results:
+ returnValue(results[0])
+ else:
+ returnValue(None)
+
def getExternalProxyAssignments(self):
"""
Retrieve proxy assignments for locations and resources from the
@@ -1170,7 +1193,6 @@
attributeToSearch = "guid"
valuesToFetch = guids
-
while valuesToFetch:
results = []
@@ -1216,7 +1238,7 @@
# Switch to the LDAP attribute used for identifying members
# for subsequent iterations. If memberIdAttr is not specified
# in the config, we'll search using dn.
- attributeToSearch = memberIdAttr if memberIdAttr else "dn"
+ attributeToSearch = "memberIdAttr" if memberIdAttr else "dn"
returnValue(recordsByAlias.values())
Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -957,6 +957,14 @@
def expandedGroupMemberships(self):
return self.groupMemberships(infinity=True)
+ def groupsChanged(self):
+ """
+ A callback indicating the directory group membership for this principal
+ has changed. Update the cache token for this principal so the PROPFIND
+ response cache is invalidated.
+ """
+ return self.cacheNotifier.changed()
+
def principalCollections(self):
return self.parent.principalCollections()
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_ldapdirectory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -43,6 +43,7 @@
"firstName" : "givenName",
"lastName" : "sn",
"guid" : "generateduid",
+ "memberIDAttr" : "generateduid",
}
entries = [
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_livedirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_livedirectory.py 2012-08-17 00:11:32 UTC (rev 9720)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_livedirectory.py 2012-08-17 01:54:53 UTC (rev 9721)
@@ -186,5 +186,8 @@
class LiveODDirectoryServiceCase(LiveDirectoryTests, TestCase):
def setUp(self):
- params = {}
+ params = {
+ "augmentService":
+ augment.AugmentXMLDB(xmlFiles=(augmentsFile.path,)),
+ }
self.svc = OpenDirectoryService(params)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120816/45e4ef60/attachment-0001.html>
More information about the calendarserver-changes
mailing list