See ChangeLog

Monotone-Parent: 99ca451495fc28364e0d775f0a4b950f0df4164d
Monotone-Revision: 740d7bf9e85e6faf504cb29387d81a224a6a92e9

Monotone-Author: ludovic@Sophos.ca
Monotone-Date: 2009-08-03T15:46:02
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Ludovic Marcotte
2009-08-03 15:46:02 +00:00
parent 49d7927566
commit f1df83e44c
12 changed files with 195 additions and 469 deletions

View File

@@ -1,3 +1,11 @@
2009-08-03 Ludovic Marcotte <lmarcotte@inverse.ca>
* Dropped the current caching subsystem based on
GNUstep's DO and replaced it with memcached. This
is much more efficient and scalable than DO and will
also prevent obscure libffi/libffcall crashes on
various platforms.
2009-08-03 Francis Lachapelle <flachapelle@inverse.ca>
* UI/Scheduler/UIxCalView.m ([UIxCalView -setCurrentView:]): avoid

View File

@@ -128,6 +128,7 @@ endif
ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX)
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
ADDITIONAL_LDFLAGS += -lmemcached
-include GNUmakefile.preamble
ifneq ($(FHS_INSTALL_ROOT),)

View File

@@ -21,7 +21,6 @@
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSLock.h>
#import <Foundation/NSString.h>
@@ -309,7 +308,7 @@ static NSLock *lock = nil;
if (!currentUser)
{
currentUser = [NSMutableDictionary dictionary];
[[SOGoCache sharedCache] cacheAttributes: currentUser forLogin: login];
[[SOGoCache sharedCache] cacheValues: currentUser ofType: @"attributes" forLogin: login];
}
[currentUser setObject: password forKey: @"password"];
}
@@ -417,34 +416,18 @@ static NSLock *lock = nil;
#endif
key = [newUser objectForKey: @"c_uid"];
if (key)
[[SOGoCache sharedCache] cacheAttributes: newUser forLogin: key];
{
[[SOGoCache sharedCache] cacheValues: newUser ofType: @"attributes" forLogin: key];
}
emails = [[newUser objectForKey: @"emails"] objectEnumerator];
while ((key = [emails nextObject]))
{
[[SOGoCache sharedCache] cacheAttributes: newUser forLogin: key];
[[SOGoCache sharedCache] cacheValues: newUser ofType: @"attributes" forLogin: key];
}
#if defined(THREADSAFE)
[lock unlock];
#endif
// We propagate the loaded LDAP attributes to other sogod instances
// which will cache them in SOGoCache (excluding for the instance
// that actually posts the notification)
if ([newUser objectForKey: @"c_uid"])
{
NSMutableDictionary *d;
d = [NSMutableDictionary dictionary];
[d setObject: newUser forKey: @"values"];
[d setObject: [newUser objectForKey: @"c_uid"]
forKey: @"uid"];
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
postNotificationName: @"SOGoUserAttributesHaveLoaded"
object: nil
userInfo: d
deliverImmediately: YES];
}
}
- (NSDictionary *) contactInfosForUserWithUIDorEmail: (NSString *) uid

View File

@@ -1,6 +1,6 @@
/* NSDictionary+DAV.m - this file is part of SOGo
*
* Copyright (C) 2008 Inverse inc.
* Copyright (C) 2008-2009 Inverse inc.
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*

View File

@@ -255,9 +255,12 @@ NSString *jsonNullString = @"null";
- (BOOL)scanJSONNumber:(NSNumber **)number
{
NSDecimal decimal;
BOOL result = [self scanDecimal:&decimal];
*number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
//NSDecimal decimal;
//BOOL result = [self scanDecimal:&decimal];
//*number = [NSDecimalNumber decimalNumberWithDecimal:decimal];
int value;
BOOL result = [self scanInt: &value];
*number = [NSNumber numberWithInt: value];
return result;
}

View File

@@ -26,6 +26,8 @@
#import <Foundation/NSObject.h>
#include <libmemcached/memcached.h>
@class NSMutableDictionary;
@class NSString;
@class NSTimer;
@@ -39,6 +41,8 @@
{
@private
NSTimer *_cleanupTimer;
memcached_server_st *servers;
memcached_st *handle;
}
+ (NSTimeInterval) cleanupInterval;
@@ -54,15 +58,13 @@
- (void) registerUser: (SOGoUser *) user;
- (id) userNamed: (NSString *) name;
- (void) cacheAttributes: (NSDictionary *) theAttributes
forLogin: (NSString *) theLogin;
- (NSMutableDictionary *) userAttributesForLogin: (NSString *) theLogin;
- (SOGoUserDefaults *) userDefaultsForLogin: (NSString *) theLogin;
- (SOGoUserDefaults *) userSettingsForLogin: (NSString *) theLogin;
- (NSDictionary *) userDefaultsForLogin: (NSString *) theLogin;
- (NSDictionary *) userSettingsForLogin: (NSString *) theLogin;
- (void) setDefaults: (SOGoUserDefaults *) theDefaults
forLogin: (NSString *) theLogin
key: (NSString *) theKey;
- (void) cacheValues: (NSDictionary *) theAttributes
ofType: (NSString *) theType
forLogin: (NSString *) theLogin;
@end

View File

@@ -22,26 +22,16 @@
*/
/*
* [ Structure ]
* users: key = user ID value = NSMutableDictionary instance
* value: key = @"user" value = SOGOUser instance
* key = @"cleanupDate" value = NSDate instance
* key = @"defaults" value = SOGoUserDefaults instance
* key = @"settings" value = SOGoUserDefaults instance
* key = @"attributes" value = NSDictionary instance (attributes from LDAP)
* [ Cache Structure ]
*
* [ Workflows - processes A and B ]
*
* A cache user defaults and posts the notification
* B ....
*
* B crashes
* B receives a notificaion update
* users value = instances of SOGoUser > flushed after the completion of every SOGo requests
* <uid>+defaults value = NSDictionary instance > user's defaults
* <uid>+settings value = NSDictionary instance > user's settings
* <uid>+attributes value = NSMutableDictionary instance > user's LDAP attributes
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSLock.h>
#import <Foundation/NSString.h>
@@ -57,6 +47,8 @@
#import "SOGoCache.h"
#import "NSDictionary+BSJSONAdditions.h"
// We define the default value for cleaning up cached
// users' preferences. This value should be relatively
// high to avoid useless database calls.
@@ -65,6 +57,8 @@ static NSTimeInterval cleanupInterval = 300;
static NSMutableDictionary *cache = nil;
static NSMutableDictionary *users = nil;
static NSString *memcachedServerName = @"localhost";
static SOGoCache *sharedCache = nil;
#if defined(THREADSAFE)
@@ -91,7 +85,7 @@ static NSLock *lock;
[lock lock];
#endif
if (!sharedCache)
sharedCache = [self new];
sharedCache = [[self alloc] init];
#if defined(THREADSAFE)
[lock unlock];
#endif
@@ -105,6 +99,10 @@ static NSLock *lock;
[lock lock];
#endif
[cache removeAllObjects];
// This is essential for refetching the cached values in case something has changed
// accross various sogod processes
[users removeAllObjects];
#if defined(THREADSAFE)
[lock unlock];
#endif
@@ -115,41 +113,11 @@ static NSLock *lock;
if ((self = [super init]))
{
NSString *cleanupSetting;
memcached_return error;
cache = [[NSMutableDictionary alloc] init];
users = [[NSMutableDictionary alloc] init];
// We register ourself for notifications
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_userAttributesHaveLoaded:)
name: @"SOGoUserAttributesHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_userDefaultsHaveLoaded:)
name: @"SOGoUserDefaultsHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_userDefaultsHaveChanged:)
name: @"SOGoUserDefaultsHaveChanged"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_userSettingsHaveLoaded:)
name: @"SOGoUserSettingsHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(_userSettingsHaveChanged:)
name: @"SOGoUserSettingsHaveChanged"
object: nil];
// We fire our timer that will cleanup cache entries
cleanupSetting = [[NSUserDefaults standardUserDefaults]
objectForKey: @"SOGoCacheCleanupInterval"];
@@ -157,13 +125,16 @@ static NSLock *lock;
if (cleanupSetting && [cleanupSetting doubleValue] > 0.0)
cleanupInterval = [cleanupSetting doubleValue];
_cleanupTimer = [NSTimer scheduledTimerWithTimeInterval: cleanupInterval
target: self
selector: @selector(_cleanupSources)
userInfo: nil
repeats: YES];
[self logWithFormat: @"Cache cleanup interval set every %f seconds",
[self logWithFormat: @"Cache cleanup interval set every %f seconds for memcached",
cleanupInterval];
handle = memcached_create(NULL);
if (handle)
{
servers = memcached_server_list_append(NULL, [memcachedServerName UTF8String], 11211, &error);
error = memcached_server_push(handle, servers);
}
}
return self;
@@ -171,31 +142,8 @@ static NSLock *lock;
- (void) dealloc
{
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: @"SOGoUserAttributesHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: @"SOGoUserDefaultsHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: @"SOGoUserDefaultsHaveChanged"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: @"SOGoUserSettingsHaveLoaded"
object: nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver: self
name: @"SOGoUserSettingsHaveChanged"
object: nil];
memcached_server_free(servers);
memcached_free(handle);
[cache release];
[users release];
[super dealloc];
@@ -269,21 +217,10 @@ static NSLock *lock;
- (void) registerUser: (SOGoUser *) user
{
NSData *cleanupDate;
#if defined(THREADSAFE)
[lock lock];
#endif
cleanupDate = [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]];
if (![users objectForKey: [user login]])
[users setObject: [NSMutableDictionary dictionary] forKey: [user login]];
[[users objectForKey: [user login]] setObject: user forKey: @"user"];
[[users objectForKey: [user login]] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
[users setObject: user forKey: [user login]];
#if defined(THREADSAFE)
[lock unlock];
#endif
@@ -291,260 +228,92 @@ static NSLock *lock;
- (id) userNamed: (NSString *) name
{
return [[users objectForKey: name] objectForKey: @"user"];
return [users objectForKey: name];
}
- (void) cacheAttributes: (NSDictionary *) theAttributes
forLogin: (NSString *) theLogin
//
// For non-blocking cache method, see memcached_behavior_set and MEMCACHED_BEHAVIOR_NO_BLOCK
// memcached is thread-safe so no need to lock here.
//
- (void) cacheValues: (NSDictionary *) theAttributes
ofType: (NSString *) theType
forLogin: (NSString *) theLogin
{
if (![users objectForKey: theLogin])
[users setObject: [NSMutableDictionary dictionary] forKey: theLogin];
memcached_return error;
const char *key, *value;
unsigned int len, vlen;
[[users objectForKey: theLogin] setObject: theAttributes forKey: @"attributes"];
[[users objectForKey: theLogin] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
if (!handle)
return;
key = [[NSString stringWithFormat: @"%@+%@", theLogin, theType] UTF8String];
len = strlen(key);
value = [[theAttributes jsonStringValue] UTF8String];
vlen = strlen(value);
error = memcached_set(handle, key, len, value, vlen, cleanupInterval, 0);
if (error != MEMCACHED_SUCCESS)
[self logWithFormat: @"memcached error: unable to cache values with subtype %@ for user %@", theType, theLogin];
//else
//[self logWithFormat: @"memcached: cached values (%s) with subtype %@ for user %@", value, theType, theLogin];
}
- (NSDictionary *) _valuesOfType: (NSString *) theType
forLogin: (NSString *) theLogin
{
NSDictionary *d;
memcached_return rc;
const char *key;
char *s;
unsigned int len, vlen, flags;
if (!handle)
return nil;
key = [[NSString stringWithFormat: @"%@+%@", theLogin, theType] UTF8String];
len = strlen(key);
d = nil;
s = memcached_get(handle, key, len, &vlen, &flags, &rc);
if (rc == MEMCACHED_SUCCESS && s)
{
NSString *v;
v = [NSString stringWithUTF8String: s];
d = [NSDictionary dictionaryWithJSONString: v];
//[self logWithFormat: @"read values (%@) for subtype %@ for user %@", [d description], theType, theLogin];
free(s);
}
return d;
}
- (NSMutableDictionary *) userAttributesForLogin: (NSString *) theLogin
{
return [[users objectForKey: theLogin] objectForKey: @"attributes"];
id o;
o = [self _valuesOfType: @"attributes" forLogin: theLogin];
if (o)
return [NSMutableDictionary dictionaryWithDictionary: o];
return nil;
}
- (SOGoUserDefaults *) userDefaultsForLogin: (NSString *) theLogin
- (NSDictionary *) userDefaultsForLogin: (NSString *) theLogin
{
return [[users objectForKey: theLogin] objectForKey: @"defaults"];
return [self _valuesOfType: @"defaults" forLogin: theLogin];
}
- (SOGoUserDefaults *) userSettingsForLogin: (NSString *) theLogin
- (NSDictionary *) userSettingsForLogin: (NSString *) theLogin
{
return [[users objectForKey: theLogin] objectForKey: @"settings"];
}
//
//
//
- (void) setDefaults: (SOGoUserDefaults *) theDefaults
forLogin: (NSString *) theLogin
key: (NSString *) theKey
{
if (![users objectForKey: theLogin])
[users setObject: [NSMutableDictionary dictionary] forKey: theLogin];
[[users objectForKey: theLogin] setObject: theDefaults forKey: theKey];
[[users objectForKey: theLogin] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
//NSLog(@"Set %@ to %@", theKey, [users objectForKey: theLogin]);
}
//
// Notification callbacks.
//
- (void) _cacheValues: (NSDictionary *) theValues
login: (NSString *) theLogin
url: (NSString *) theURL
key: (NSString *) theKey
{
SOGoUserDefaults *defaults;
NSURL *url;
#if defined(THREADSAFE)
[lock lock];
#endif
url = [[[NSURL alloc] initWithString: theURL] autorelease];
defaults = [[[SOGoUserDefaults alloc] initWithTableURL: url
uid: theLogin
fieldName: [NSString stringWithFormat: @"c_%@", theKey]
shouldPropagate: YES]
autorelease];
[defaults setValues: theValues];
[self setDefaults: defaults forLogin: theLogin key: theKey];
#if defined(THREADSAFE)
[lock unlock];
#endif
}
//
//
//
- (void) _userAttributesHaveLoaded: (NSNotification *) theNotification
{
NSString *uid;
uid = [[theNotification userInfo] objectForKey: @"uid"];
//NSLog(@"Caching user attributes for UID: %@", uid);
if (![self userAttributesForLogin: uid])
{
NSEnumerator *emails;
NSDictionary *values;
NSString *key;
if (![users objectForKey: uid])
[users setObject: [NSMutableDictionary dictionary] forKey: uid];
values = [[theNotification userInfo] objectForKey: @"values"];
[self cacheAttributes: values forLogin: uid];
emails = [[values objectForKey: @"emails"] objectEnumerator];
while ((key = [emails nextObject]))
{
[self cacheAttributes: values forLogin: key];
}
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
}
}
//
//
//
- (void) _userDefaultsHaveLoaded: (NSNotification *) theNotification
{
NSString *uid;
uid = [[theNotification userInfo] objectForKey: @"uid"];
//NSLog(@"Loading user defaults for UID: %@", uid);
if (![self userDefaultsForLogin: uid])
{
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
login: uid
url: [[theNotification userInfo] objectForKey: @"url"]
key: @"defaults"];
}
}
//
//
//
- (void) _userDefaultsHaveChanged: (NSNotification *) theNotification
{
SOGoUser *user;
SOGoUserDefaults *defaults;
NSString *uid;
uid = [[theNotification userInfo] objectForKey: @"uid"];
// When the user defaults changed, we must invalidate the
// ivar language for the user object.
user = [self userNamed: uid];
if (user)
[user invalidateLanguage];
//NSLog(@"Updating user defaults for UID: %@", uid);
defaults = (SOGoUserDefaults *)[self userDefaultsForLogin: uid];
if (defaults)
{
#if defined(THREADSAFE)
[lock lock];
#endif
[defaults setValues: [[theNotification userInfo] objectForKey: @"values"]];
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
#if defined(THREADSAFE)
[lock unlock];
#endif
}
else
{
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
login: uid
url: [[theNotification userInfo] objectForKey: @"url"]
key: @"defaults"];
}
}
//
//
//
- (void) _userSettingsHaveLoaded: (NSNotification *) theNotification
{
NSString *uid;
uid = [[theNotification userInfo] objectForKey: @"uid"];
//NSLog(@"Loading user settings for UID: %@", uid);
if (![self userSettingsForLogin: uid])
{
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
login: uid
url: [[theNotification userInfo] objectForKey: @"url"]
key: @"settings"];
}
}
//
//
//
- (void) _userSettingsHaveChanged: (NSNotification *) theNotification
{
SOGoUserDefaults *settings;
NSString *uid;
uid = [[theNotification userInfo] objectForKey: @"uid"];
//NSLog(@"Updating user settings for UID: %@", uid);
settings = (SOGoUserDefaults *)[self userSettingsForLogin: uid];
if (settings)
{
#if defined(THREADSAFE)
[lock lock];
#endif
[settings setValues: [[theNotification userInfo] objectForKey: @"values"]];
[[users objectForKey: uid] setObject: [[NSDate date] addTimeInterval: [SOGoCache cleanupInterval]]
forKey: @"cleanupDate"];
#if defined(THREADSAFE)
[lock unlock];
#endif
}
else
{
[self _cacheValues: [[theNotification userInfo] objectForKey: @"values"]
login: uid
url: [[theNotification userInfo] objectForKey: @"url"]
key: @"settings"];
}
}
//
//
//
- (void) _cleanupSources
{
NSDictionary *currentEntry;
NSEnumerator *userIDs;
NSString *currentID;
NSDate *now;
unsigned int count;
#if defined(THREADSAFE)
[lock lock];
#endif
now = [NSDate date];
// We cleanup the user cache
userIDs = [[users allKeys] objectEnumerator];
count = 0;
while ((currentID = [userIDs nextObject]))
{
currentEntry = [users objectForKey: currentID];
if ([now earlierDate: [currentEntry objectForKey: @"cleanupDate"]] == now)
{
[users removeObjectForKey: currentID];
count++;
}
}
if (count)
[self logWithFormat: @"cleaned %d users records from users cache",
count];
#if defined(THREADSAFE)
[lock unlock];
#endif
return [self _valuesOfType: @"settings" forLogin: theLogin];
}
@end

View File

@@ -64,6 +64,7 @@ extern NSString *SOGoWeekStartFirstFullWeek;
@interface SOGoUser : SoUser
{
SOGoUserDefaults *_defaults, *_settings;
SOGoUserFolder *homeFolder;
NSString *currentPassword;
NSString *language;

View File

@@ -23,7 +23,6 @@
#import <Foundation/NSArray.h>
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSEnumerator.h>
#import <Foundation/NSNull.h>
#import <Foundation/NSTimeZone.h>
@@ -257,6 +256,9 @@ _timeValue (NSString *key)
{
LDAPUserManager *um;
NSString *realUID;
_defaults = nil;
_settings = nil;
// We propagate the cache if we do NOT trust the login names.
// When trusting login names, we 'assume' we're dealing with a
@@ -300,6 +302,8 @@ _timeValue (NSString *key)
- (void) dealloc
{
[_defaults release];
[_settings release];
[allEmails release];
[currentPassword release];
[cn release];
@@ -454,7 +458,6 @@ _timeValue (NSString *key)
uid: login
fieldName: @"c_defaults"
shouldPropagate: propagateCache];
[o autorelease];
return o;
}
@@ -467,113 +470,91 @@ _timeValue (NSString *key)
uid: login
fieldName: @"c_settings"
shouldPropagate: propagateCache];
[o autorelease];
return o;
}
- (NSUserDefaults *) userDefaults
{
SOGoUserDefaults *defaults;
NSDictionary *values;
NSMutableDictionary *d;
defaults = [[SOGoCache sharedCache] userDefaultsForLogin: login];
if (!defaults)
if (!_defaults)
{
defaults = [self primaryUserDefaults];
if (defaults)
_defaults = [self primaryUserDefaults];
if (_defaults)
{
[defaults fetchProfile];
values = [defaults values];
values = [[SOGoCache sharedCache] userDefaultsForLogin: login];
if (values)
{
// See explanation in -language
[self invalidateLanguage];
// Required parameters for the Web interface. This will trigger the
// preferences to load so it's important to leave those calls here.
if (![[defaults stringForKey: @"ReplyPlacement"] length])
[defaults setObject: defaultReplyPlacement forKey: @"ReplyPlacement"];
if (![[defaults stringForKey: @"SignaturePlacement"] length])
[defaults setObject: defaultSignaturePlacement forKey: @"SignaturePlacement"];
if (![[defaults stringForKey: @"MessageForwarding"] length])
[defaults setObject: defaultMessageForwarding forKey: @"MessageForwarding"];
if (![[defaults stringForKey: @"MessageCheck"] length])
[defaults setObject: defaultMessageCheck forKey: @"MessageCheck"];
// We propagate the loaded user defaults to other sogod instances
// which will cache them in SOGoCache (including for the instance
// that actually posts the notification)
d = [NSMutableDictionary dictionary];
[d setObject: values forKey: @"values"];
[d setObject: login forKey: @"uid"];
[d setObject: [SOGoProfileURL absoluteString] forKey: @"url"];
[[SOGoCache sharedCache] setDefaults: defaults
forLogin: login key: @"defaults"];
if (propagateCache)
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
postNotificationName: @"SOGoUserDefaultsHaveLoaded"
object: nil
userInfo: d
deliverImmediately: YES];
[_defaults setValues: values];
}
else
{
[_defaults fetchProfile];
values = [_defaults values];
if (values)
{
// Required parameters for the Web interface. This will trigger the
// preferences to load so it's important to leave those calls here.
if (![[_defaults stringForKey: @"ReplyPlacement"] length])
[_defaults setObject: defaultReplyPlacement forKey: @"ReplyPlacement"];
if (![[_defaults stringForKey: @"SignaturePlacement"] length])
[_defaults setObject: defaultSignaturePlacement forKey: @"SignaturePlacement"];
if (![[_defaults stringForKey: @"MessageForwarding"] length])
[_defaults setObject: defaultMessageForwarding forKey: @"MessageForwarding"];
if (![[_defaults stringForKey: @"MessageCheck"] length])
[_defaults setObject: defaultMessageCheck forKey: @"MessageCheck"];
[[SOGoCache sharedCache] cacheValues: [_defaults values] ofType: @"defaults" forLogin: login];
}
}
// See explanation in -language
[self invalidateLanguage];
}
}
//else
// NSLog(@"User defaults cache hit for %@", login);
return (NSUserDefaults *) defaults;
return (NSUserDefaults *) _defaults;
}
- (NSUserDefaults *) userSettings
{
SOGoUserDefaults *settings;
NSDictionary *values;
settings = [[SOGoCache sharedCache] userSettingsForLogin: login];
if (!settings)
if (!_settings)
{
NSMutableDictionary *d;
settings = [self primaryUserSettings];
if (settings)
_settings = [self primaryUserSettings];
if (_settings)
{
[settings fetchProfile];
values = [settings values];
values = [[SOGoCache sharedCache] userSettingsForLogin: login];
if (values)
{
// See explanation in -language
[self invalidateLanguage];
// We propagate the loaded user settings to other sogod instances
// which will cache them in SOGoCache (including for the instance
// that actually posts the notification)
d = [NSMutableDictionary dictionary];
[d setObject: values forKey: @"values"];
[d setObject: login forKey: @"uid"];
[d setObject: [SOGoProfileURL absoluteString] forKey: @"url"];
[[SOGoCache sharedCache] setDefaults: settings forLogin: login key: @"settings"];
if (propagateCache)
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
postNotificationName: @"SOGoUserSettingsHaveLoaded"
object: nil
userInfo: d
deliverImmediately: YES];
[_settings setValues: values];
}
else
{
[_settings fetchProfile];
values = [_settings values];
if (values)
{
[[SOGoCache sharedCache] cacheValues: values ofType: @"settings" forLogin: login];
}
}
// See explanation in -language
[self invalidateLanguage];
}
}
//else
// NSLog(@"User settings cache hit for %@", login);
return (NSUserDefaults *) settings;
return (NSUserDefaults *) _settings;
}
- (void) invalidateLanguage
@@ -586,7 +567,7 @@ _timeValue (NSString *key)
if (![language length])
{
language = [[self userDefaults] stringForKey: @"Language"];
// This is a hack until we handle the connection errors to the db a
// This is a workaround until we handle the connection errors to the db in a
// better way. It enables us to avoid retrieving the userDefaults too
// many times when the DB is down, causing a huge delay.
if (![language length])

View File

@@ -1,6 +1,6 @@
/*
Copyright (C) 2005 SKYRIX Software AG
Copyright (C) 2008-2009 Inverse inc.
Copyright (C) 2005 SKYRIX Software AG
This file is part of SOGo.
@@ -43,7 +43,6 @@
NSURL *url;
NSString *uid;
NSString *fieldName;
NSCalendarDate *lastFetch;
NSMutableDictionary *values;
BOOL propagateCache;

View File

@@ -21,7 +21,6 @@
*/
#import <Foundation/NSCalendarDate.h>
#import <Foundation/NSDistributedNotificationCenter.h>
#import <Foundation/NSPropertyList.h>
#import <Foundation/NSUserDefaults.h>
#import <Foundation/NSValue.h>
@@ -74,7 +73,6 @@ static NSString *uidColumnName = @"c_uid";
- (void) dealloc
{
[values release];
[lastFetch release];
[url release];
[uid release];
[fieldName release];
@@ -160,7 +158,6 @@ static NSString *uidColumnName = @"c_uid";
[values addEntriesFromDictionary: v];
}
ASSIGN(lastFetch, [NSCalendarDate date]);
defFlags.modified = NO;
rc = YES;
}
@@ -295,25 +292,10 @@ static NSString *uidColumnName = @"c_uid";
if (rc)
{
NSMutableDictionary *d;
d = [NSMutableDictionary dictionary];
[d setObject: values forKey: @"values"];
[d setObject: uid forKey: @"uid"];
[d setObject: [url absoluteString] forKey: @"url"];
[[SOGoCache sharedCache] setDefaults: self
forLogin: uid
key: ([fieldName isEqualToString: @"c_defaults"] ? @"defaults" : @"settings")];
if (propagateCache)
[(NSDistributedNotificationCenter *)[NSDistributedNotificationCenter defaultCenter]
postNotificationName: ([fieldName isEqualToString: @"c_defaults"]
? @"SOGoUserDefaultsHaveChanged"
: @"SOGoUserSettingsHaveChanged")
object: nil
userInfo: d
deliverImmediately: YES];
[[SOGoCache sharedCache] cacheValues: values
ofType: ([fieldName isEqualToString: @"c_defaults"] ? @"defaults" : @"settings")
forLogin: uid];
}
return rc;
@@ -344,7 +326,6 @@ static NSString *uidColumnName = @"c_uid";
values = [[NSMutableDictionary alloc] init];
[values addEntriesFromDictionary: theValues];
ASSIGN(lastFetch, [NSCalendarDate date]);
defFlags.modified = NO;
defFlags.isNew = NO;
}
@@ -429,8 +410,6 @@ static NSString *uidColumnName = @"c_uid";
- (void) flush
{
[values removeAllObjects];
[lastFetch release];
lastFetch = nil;
defFlags.modified = NO;
defFlags.isNew = NO;
}

View File

@@ -10,9 +10,9 @@ Group: Productivity/Groupware
Source: SOGo-%{sogo_version}.tar.gz
Prefix: %{sogo_prefix}
AutoReqProv: off
Requires: gnustep-base sope%{sope_major_version}%{sope_minor_version}-core httpd sope%{sope_major_version}%{sope_minor_version}-core sope%{sope_major_version}%{sope_minor_version}-appserver sope%{sope_major_version}%{sope_minor_version}-ldap sope%{sope_major_version}%{sope_minor_version}-cards sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore
Requires: gnustep-base sope%{sope_major_version}%{sope_minor_version}-core httpd sope%{sope_major_version}%{sope_minor_version}-core sope%{sope_major_version}%{sope_minor_version}-appserver sope%{sope_major_version}%{sope_minor_version}-ldap sope%{sope_major_version}%{sope_minor_version}-cards sope%{sope_major_version}%{sope_minor_version}-gdl1-contentstore memcached libmemcached
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
BuildPreReq: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel
BuildPreReq: gcc-objc gnustep-base gnustep-make sope%{sope_major_version}%{sope_minor_version}-appserver-devel sope%{sope_major_version}%{sope_minor_version}-core-devel sope%{sope_major_version}%{sope_minor_version}-ldap-devel sope%{sope_major_version}%{sope_minor_version}-mime-devel sope%{sope_major_version}%{sope_minor_version}-xml-devel sope%{sope_major_version}%{sope_minor_version}-gdl1-devel libmemcached-devel
%description
SOGo is a groupware server built around OpenGroupware.org (OGo) and
the SOPE application server. It focuses on scalability.