From: helge Date: Thu, 21 Jul 2005 13:40:52 +0000 (+0000) Subject: replaced SOGoLRUCache with NSMutableDictionary X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da72d88e86832cd5c18226a9204b432f7b8cbc0e;p=scalable-opengroupware.org replaced SOGoLRUCache with NSMutableDictionary added a new shared-mailbox fetch method git-svn-id: http://svn.opengroupware.org/SOGo/trunk@872 d1b88da0-ebda-0310-925b-ed51d893ca5b --- diff --git a/SOGo/SoObjects/SOGo/AgenorUserManager.h b/SOGo/SoObjects/SOGo/AgenorUserManager.h index 9b1c4f05..957349b0 100644 --- a/SOGo/SoObjects/SOGo/AgenorUserManager.h +++ b/SOGo/SoObjects/SOGo/AgenorUserManager.h @@ -30,21 +30,22 @@ TODO: document */ -@class NSString, NSArray, NSURL, NSUserDefaults; -@class SOGoLRUCache; +@class NSString, NSArray, NSURL, NSUserDefaults, NSMutableDictionary, NSTimer; +@class NSDictionary; @class iCalPerson; @interface AgenorUserManager : NSObject { - SOGoLRUCache *cnCache; - SOGoLRUCache *serverCache; - SOGoLRUCache *uidCache; - SOGoLRUCache *emailCache; - SOGoLRUCache *shareStoreCache; - SOGoLRUCache *shareEMailCache; - SOGoLRUCache *changeInternetAccessCache; - SOGoLRUCache *internetAutoresponderFlagCache; - SOGoLRUCache *intranetAutoresponderFlagCache; + NSMutableDictionary *cnCache; + NSMutableDictionary *serverCache; + NSMutableDictionary *uidCache; + NSMutableDictionary *emailCache; + NSMutableDictionary *shareStoreCache; + NSMutableDictionary *shareEMailCache; + NSMutableDictionary *changeInternetAccessCache; + NSMutableDictionary *internetAutoresponderFlagCache; + NSMutableDictionary *intranetAutoresponderFlagCache; + NSTimer *gcTimer; } + (id)sharedUserManager; @@ -68,6 +69,7 @@ - (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid; - (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid; +- (NSDictionary *)getSharedMailboxesAndEMailsForUID:(NSString *)_uid; - (NSURL *)getFreeBusyURLForUID:(NSString *)_uid; diff --git a/SOGo/SoObjects/SOGo/AgenorUserManager.m b/SOGo/SoObjects/SOGo/AgenorUserManager.m index fa7d3c7d..b4cd1294 100644 --- a/SOGo/SoObjects/SOGo/AgenorUserManager.m +++ b/SOGo/SoObjects/SOGo/AgenorUserManager.m @@ -67,6 +67,8 @@ static NSURL *AgenorProfileURL = nil; static NSArray *fromEMailAttrs = nil; +static unsigned PoolScanInterval = 5 * 60 /* every five minutes */; + + (void)initialize { static BOOL didInit = NO; NSUserDefaults *ud; @@ -106,6 +108,13 @@ static NSArray *fromEMailAttrs = nil; NSLog(@"ERROR: could not parse AgenorProfileURL: '%@'", tmp); else NSLog(@"Note: using profile at: %@", [AgenorProfileURL absoluteString]); + + PoolScanInterval = [[ud objectForKey:@"AgenorCacheCheckInterval"] intValue]; + if (PoolScanInterval == 0) + PoolScanInterval = 60 * 60 /* every hour */; + NSLog(@"AgenorUserManager: flushing caches every %d minutes " + @"(AgenorCacheCheckInterval)", + PoolScanInterval / 60); } + (id)sharedUserManager { @@ -118,23 +127,35 @@ static NSArray *fromEMailAttrs = nil; - (id)init { self = [super init]; if(self) { - self->serverCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; - self->cnCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; - self->uidCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; - self->emailCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; - self->shareStoreCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; - self->shareEMailCache = [[SOGoLRUCache alloc] initWithCacheSize:10000]; + self->serverCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; + self->cnCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; + self->uidCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; + self->emailCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; + self->shareStoreCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; + self->shareEMailCache = + [[NSMutableDictionary alloc] initWithCapacity:10000]; self->changeInternetAccessCache = - [[SOGoLRUCache alloc] initWithCacheSize:10000]; + [[NSMutableDictionary alloc] initWithCapacity:10000]; self->internetAutoresponderFlagCache = - [[SOGoLRUCache alloc] initWithCacheSize:10000]; + [[NSMutableDictionary alloc] initWithCapacity:10000]; self->intranetAutoresponderFlagCache = - [[SOGoLRUCache alloc] initWithCacheSize:10000]; + [[NSMutableDictionary alloc] initWithCapacity:10000]; + + self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval: + PoolScanInterval + target:self selector:@selector(_garbageCollect:) + userInfo:nil repeats:YES] retain]; } return self; } - (void)dealloc { + if (self->gcTimer) [self->gcTimer invalidate]; [self->serverCache release]; [self->cnCache release]; [self->uidCache release]; @@ -144,9 +165,32 @@ static NSArray *fromEMailAttrs = nil; [self->changeInternetAccessCache release]; [self->internetAutoresponderFlagCache release]; [self->intranetAutoresponderFlagCache release]; + [self->gcTimer release]; [super dealloc]; } +/* cache */ + +- (void)flush { + [self->cnCache removeAllObjects]; + [self->serverCache removeAllObjects]; + [self->uidCache removeAllObjects]; + [self->emailCache removeAllObjects]; + [self->shareStoreCache removeAllObjects]; + [self->shareEMailCache removeAllObjects]; + + [self->changeInternetAccessCache removeAllObjects]; + [self->internetAutoresponderFlagCache removeAllObjects]; + [self->intranetAutoresponderFlagCache removeAllObjects]; +} + +- (void)_garbageCollect:(NSTimer *)_timer { + [self debugWithFormat:@"flushing caches."]; + [self flush]; +} + +/* LDAP */ + - (NGLdapConnection *)ldapConnection { static NGLdapConnection *ldapConnection = nil; if(!ldapConnection) { @@ -164,7 +208,7 @@ static NSArray *fromEMailAttrs = nil; - (void)_cacheCN:(NSString *)_cn forUID:(NSString *)_uid { if (_cn == nil) return; - [self->cnCache addObject:_cn forKey:_uid]; + [self->cnCache setObject:_cn forKey:_uid]; } - (NSString *)_cachedCNForUID:(NSString *)_uid { return [self->cnCache objectForKey:_uid]; @@ -172,7 +216,7 @@ static NSArray *fromEMailAttrs = nil; - (void)_cacheServer:(NSString *)_server forUID:(NSString *)_uid { if (_server == nil) return; - [self->serverCache addObject:_server forKey:_uid]; + [self->serverCache setObject:_server forKey:_uid]; } - (NSString *)_cachedServerForUID:(NSString *)_uid { return [self->serverCache objectForKey:_uid]; @@ -180,7 +224,7 @@ static NSArray *fromEMailAttrs = nil; - (void)_cacheEmail:(NSString *)_email forUID:(NSString *)_uid { if (_email == nil) return; - [self->emailCache addObject:_email forKey:_uid]; + [self->emailCache setObject:_email forKey:_uid]; } - (NSString *)_cachedEmailForUID:(NSString *)_uid { return [self->emailCache objectForKey:_uid]; @@ -188,7 +232,7 @@ static NSArray *fromEMailAttrs = nil; - (void)_cacheUID:(NSString *)_uid forEmail:(NSString *)_email { if (_uid == nil) return; - [self->uidCache addObject:_uid forKey:_email]; + [self->uidCache setObject:_uid forKey:_email]; } - (NSString *)_cachedUIDForEmail:(NSString *)_email { return [self->uidCache objectForKey:_email]; @@ -305,15 +349,13 @@ static NSArray *fromEMailAttrs = nil; for (i = 0; i < count; i++) { iCalPerson *p; id uid; - + p = [_persons objectAtIndex:i]; uid = [self getUIDForICalPerson:p]; - if (uid) { + if (uid != nil) [ma addObject:uid]; - } - else if (!uid && _mapStrictly) { + else if (uid == nil && _mapStrictly) [ma addObject:sharedNull]; - } } return ma; } @@ -487,6 +529,8 @@ static NSArray *fromEMailAttrs = nil; @"uid", /* required for shares */ @"mineqMelRoutage", @"mineqMelServeurPrincipal", + @"mineqMelPartages", + mailEmissionAttrName, nil]; } return attrs; @@ -689,6 +733,135 @@ static NSArray *fromEMailAttrs = nil; /* shared mailboxes */ - (NSArray *)getSharedMailboxAccountStringsForUID:(NSString *)_uid { + NSArray *k; + + k = [[self getSharedMailboxesAndEMailsForUID:_uid] allKeys]; + + /* ensure that ordering is always the same */ + return [k sortedArrayUsingSelector:@selector(compare:)]; +} + +- (NSString *)emissionEMailFromEntry:(NGLdapEntry *)_entry { + id emissionAttr; + + emissionAttr = [_entry attributeWithName:mailEmissionAttrName]; + if ([emissionAttr count] == 0) { + [self logWithFormat:@"WARNING: share has no %@ attr: %@", + mailEmissionAttrName, [_entry dn]]; + return nil; + } + + if ([emissionAttr count] > 1) { + [self logWithFormat: + @"WARNING: share has more than one value in %@ attr: %@", + mailEmissionAttrName, [_entry dn]]; + return nil; + } + + return [emissionAttr stringValueAtIndex:0]; +} + +- (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid { + NSMutableArray *shares = nil; + NGLdapConnection *conn; + EOQualifier *q; + NSString *gPattern, *cPattern; + NSEnumerator *resultEnum; + NGLdapEntry *entry; + + if ([_uid length] == 0) + return nil; + + if (!useLDAP) { + [self logWithFormat: + @"Note: LDAP access is disabled, returning no shared froms."]; + return nil; + } + + /* check cache */ + if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil) + return shares; + + /* G and C mean "emission access" */ + gPattern = [_uid stringByAppendingString:@":G"]; + cPattern = [_uid stringByAppendingString:@":C"]; + + q = [EOQualifier qualifierWithQualifierFormat: + @"((mineqMelPartages = %@) OR (mineqMelPartages = %@)) " + @"AND (objectclass = %@)", + gPattern, cPattern, shareLDAPClass]; + + conn = [self ldapConnection]; + + resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN + qualifier:q + attributes:fromEMailAttrs]; + + while ((entry = [resultEnum nextObject]) != nil) { + NSString *emissionAttr; + + if ((emissionAttr = [self emissionEMailFromEntry:entry]) == nil) + continue; + + if (shares == nil) shares = [NSMutableArray arrayWithCapacity:4]; + [shares addObject:emissionAttr]; + } + + /* ensure that ordering is always the same */ + [shares sortUsingSelector:@selector(compare:)]; + + /* cache */ + shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease]; + [self->shareEMailCache setObject:shares forKey:_uid]; + return shares; +} + +/* identities */ + +- (BOOL)hasUser:(NSString *)_uid partageAccess:(char *)_rightset + inEntry:(NGLdapEntry *)_entry +{ + NGLdapAttribute *attr; + unsigned i, count; + + attr = [_entry attributeWithName:@"mineqMelPartages"]; + if ((count = [attr count]) == 0) { + [self logWithFormat:@"WARNING: share has no 'mineqMelPartages' attr: %@", + [_entry dn]]; + return NO; + } + + for (i = 0; i < count; i++) { + NSString *p; + NSRange r; + unichar c; + register unsigned j; + + p = [attr stringValueAtIndex:i]; + r = [p rangeOfString:@":"]; + if (r.length == 0) { + [self errorWithFormat:@"Invalid mineqMelPartages value: '%@'", p]; + continue; + } + + /* check whether prefix matches, eg: "helian.h:G" */ + if (r.location != [_uid length]) /* check length */ + continue; + if (![p hasPrefix:_uid]) + continue; + + c = [p characterAtIndex:(r.location + r.length)]; + + /* check whether permissions match */ + for (j = 0; _rightset[j] != '\0'; j++) { + if (c == _rightset[j]) + return YES; + } + } + return NO; +} + +- (NSDictionary *)getSharedMailboxesAndEMailsForUID:(NSString *)_uid { /* Sample: "(&(mineqMelPartages=guizmo.g:*)(objectclass=mineqMelBoite))" @@ -699,8 +872,12 @@ static NSArray *fromEMailAttrs = nil; (uid + ".-." + share-uid) Note: shared mailboxes can be on different hosts! + + This returns a dictionary where the keys are the IMAP4 connect strings + while the values are the emitter addresses for the box or NSNull if the + uid is not allowed to emit for this box. */ - NSMutableArray *shares = nil; + NSMutableDictionary *shares = nil; NGLdapConnection *conn; EOQualifier *q; NSString *sharePattern; @@ -733,8 +910,10 @@ static NSArray *fromEMailAttrs = nil; attributes:[self mailServerDiscoveryAttributes]]; while ((entry = [resultEnum nextObject]) != nil) { - NSString *server, *shareLogin; + NSString *server, *shareLogin, *emitterAddress; id shareUid; + + /* calculate server connect string */ if ([(server = [self serverFromEntry:entry]) length] == 0) { [self errorWithFormat:@"found no mail server host for share: %@", @@ -753,86 +932,28 @@ static NSArray *fromEMailAttrs = nil; shareLogin = [shareLogin stringByAppendingString:shareUid]; if (shares == nil) - shares = [NSMutableArray arrayWithCapacity:4]; + shares = [NSMutableDictionary dictionaryWithCapacity:4]; shareLogin = [shareLogin stringByAppendingString:@"@"]; shareLogin = [shareLogin stringByAppendingString:server]; - [shares addObject:shareLogin]; - } - - /* ensure that ordering is always the same */ - [shares sortUsingSelector:@selector(compare:)]; - - /* cache */ - shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease]; - [self->shareStoreCache addObject:shares forKey:_uid]; - return shares; -} - -- (NSArray *)getSharedMailboxEMailsForUID:(NSString *)_uid { - NSMutableArray *shares = nil; - NGLdapConnection *conn; - EOQualifier *q; - NSString *gPattern, *cPattern; - NSEnumerator *resultEnum; - NGLdapEntry *entry; - - if ([_uid length] == 0) - return nil; - - if (!useLDAP) { - [self logWithFormat: - @"Note: LDAP access is disabled, returning no shared froms."]; - return nil; - } - - /* check cache */ - if ((shares = [self->shareEMailCache objectForKey:_uid]) != nil) - return shares; - - /* G and C mean "emission access" */ - gPattern = [_uid stringByAppendingString:@":G"]; - cPattern = [_uid stringByAppendingString:@":C"]; - - q = [EOQualifier qualifierWithQualifierFormat: - @"((mineqMelPartages = %@) OR (mineqMelPartages = %@)) " - @"AND (objectclass = %@)", - gPattern, cPattern, shareLDAPClass]; - - conn = [self ldapConnection]; - - resultEnum = [conn deepSearchAtBaseDN:ldapBaseDN - qualifier:q - attributes:fromEMailAttrs]; - - while ((entry = [resultEnum nextObject]) != nil) { - id emissionAttr; - emissionAttr = [entry attributeWithName:mailEmissionAttrName]; - if ([emissionAttr count] == 0) { - [self logWithFormat:@"WARNING: share has no %@ attr: %@", - mailEmissionAttrName, [entry dn]]; - continue; - } + /* calculate emitter address (check for proper access right) */ - if ([emissionAttr count] > 1) { - [self logWithFormat: - @"WARNING: share has more than one value in %@ attr: %@", - mailEmissionAttrName, [entry dn]]; - continue; - } + emitterAddress = [self hasUser:_uid partageAccess:"GC" inEntry:entry] + ? [self emissionEMailFromEntry:entry] + : nil; - emissionAttr = [emissionAttr stringValueAtIndex:0]; - if (shares == nil) shares = [NSMutableArray arrayWithCapacity:4]; - [shares addObject:emissionAttr]; + /* set value */ + + [shares setObject:(emitterAddress ? emitterAddress : (id)[NSNull null]) + forKey:shareLogin]; } - /* ensure that ordering is always the same */ - [shares sortUsingSelector:@selector(compare:)]; - /* cache */ - shares = (shares == nil) ? [NSArray array] : [[shares copy] autorelease]; - [self->shareEMailCache addObject:shares forKey:_uid]; + shares = (shares == nil) + ? [NSDictionary dictionary] + : [[shares copy] autorelease]; + [self->shareStoreCache setObject:shares forKey:_uid]; return shares; } @@ -872,7 +993,7 @@ static NSArray *fromEMailAttrs = nil; value = [self primaryIsUserAllowedToChangeSOGoInternetAccess:_uid]; bv = [NSNumber numberWithBool:value]; - [self->changeInternetAccessCache addObject:bv forKey:_uid]; + [self->changeInternetAccessCache setObject:bv forKey:_uid]; } return [bv boolValue]; } @@ -925,7 +1046,7 @@ static NSArray *fromEMailAttrs = nil; value = [self primaryIsInternetAutoresponderEnabledForUser:_uid]; bv = [NSNumber numberWithBool:value]; - [self->internetAutoresponderFlagCache addObject:bv forKey:_uid]; + [self->internetAutoresponderFlagCache setObject:bv forKey:_uid]; } return [bv boolValue]; } @@ -947,7 +1068,7 @@ static NSArray *fromEMailAttrs = nil; value = [self primaryIsIntranetAutoresponderEnabledForUser:_uid]; bv = [NSNumber numberWithBool:value]; - [self->intranetAutoresponderFlagCache addObject:bv forKey:_uid]; + [self->intranetAutoresponderFlagCache setObject:bv forKey:_uid]; } return [bv boolValue]; } diff --git a/SOGo/SoObjects/SOGo/ChangeLog b/SOGo/SoObjects/SOGo/ChangeLog index f5b83e26..c3190919 100644 --- a/SOGo/SoObjects/SOGo/ChangeLog +++ b/SOGo/SoObjects/SOGo/ChangeLog @@ -1,3 +1,10 @@ +2005-07-21 Helge Hess + + * AgenorUserManager.m: rewrote to use NSMutableDictionary instead of + SOGoLRUCache. Flush caches every hour (configurable using + 'AgenorCacheCheckInterval' default). Added method to retrieve the + shares and the emitter emails in one step. (v0.9.67) + 2005-07-20 Helge Hess * v0.9.66 diff --git a/SOGo/SoObjects/SOGo/README b/SOGo/SoObjects/SOGo/README index 08d4f335..69151e4a 100644 --- a/SOGo/SoObjects/SOGo/README +++ b/SOGo/SoObjects/SOGo/README @@ -20,3 +20,10 @@ Class Hierarchy TODO ==== - why is SOGoUserFolder an OCS folder? + + +Defaults +======== + +AgenorCacheCheckInterval - int (default: 1 hour == 3600s) +- how often to flush the LDAP caches diff --git a/SOGo/SoObjects/SOGo/SOGoLRUCache.h b/SOGo/SoObjects/SOGo/SOGoLRUCache.h index 1d29a504..a7cee3c2 100644 --- a/SOGo/SoObjects/SOGo/SOGoLRUCache.h +++ b/SOGo/SoObjects/SOGo/SOGoLRUCache.h @@ -18,16 +18,12 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ - #ifndef __SOGoLRUCache_H_ #define __SOGoLRUCache_H_ - #import - @interface SOGoLRUCache : NSObject { unsigned size; diff --git a/SOGo/SoObjects/SOGo/SOGoLRUCache.m b/SOGo/SoObjects/SOGo/SOGoLRUCache.m index 3233f771..9fdacf5c 100644 --- a/SOGo/SoObjects/SOGo/SOGoLRUCache.m +++ b/SOGo/SoObjects/SOGo/SOGoLRUCache.m @@ -18,11 +18,9 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ - -#import "SOGoLRUCache.h" -#import "common.h" +#include "SOGoLRUCache.h" +#include "common.h" @interface SOGoLRUCacheItem : NSObject { diff --git a/SOGo/SoObjects/SOGo/Version b/SOGo/SoObjects/SOGo/Version index 46a95765..191e256f 100644 --- a/SOGo/SoObjects/SOGo/Version +++ b/SOGo/SoObjects/SOGo/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=66 +SUBMINOR_VERSION:=67 # v0.9.63 requires libNGiCal v4.5.54 # v0.9.60 requires libNGiCal v4.5.49