Author: rfm
Date: Fri Mar 18 13:40:08 2016
New Revision: 39564
URL: http://svn.gna.org/viewcvs/gnustep?rev=39564&view=rev
Log:
User defaults changes to cope better with slow systems
Modified:
libs/base/trunk/ChangeLog
libs/base/trunk/Source/NSUserDefaults.m
Modified: libs/base/trunk/ChangeLog
URL:
http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/ChangeLog?rev=39564&r1=39563&r2=39564&view=diff
==============================================================================
--- libs/base/trunk/ChangeLog (original)
+++ libs/base/trunk/ChangeLog Fri Mar 18 13:40:08 2016
@@ -1,3 +1,8 @@
+2016-03-18 Richard Frith-Macdonald <[email protected]>
+
+ * Source/NSUserDefaults.m: Wait longer for locks on slow systems
+ Improve tracking of changes in persistent domains.
+
2016-03-17 Richard Frith-Macdonald <[email protected]>
* Headers/GNUstepBase/GSXML.h:
@@ -19,7 +24,7 @@
2016-03-14 Richard Frith-Macdonald <[email protected]>
- * Source/NSUserDefaults.m: Log is we break the lock.
+ * Source/NSUserDefaults.m: Log if we break the lock.
* Source/NSDistributedLock.m: Unlock if dealloc'ed while locked.
2016-03-12 Richard Frith-Macdonald <[email protected]>
Modified: libs/base/trunk/Source/NSUserDefaults.m
URL:
http://svn.gna.org/viewcvs/gnustep/libs/base/trunk/Source/NSUserDefaults.m?rev=39564&r1=39563&r2=39564&view=diff
==============================================================================
--- libs/base/trunk/Source/NSUserDefaults.m (original)
+++ libs/base/trunk/Source/NSUserDefaults.m Fri Mar 18 13:40:08 2016
@@ -116,19 +116,23 @@
@interface GSPersistentDomain : NSObject
{
NSString *name;
+ NSString *path;
NSUserDefaults *owner;
- NSDate *updated;
-@public
- BOOL modified;
NSMutableDictionary *contents;
-}
-- (NSMutableDictionary*) contents;
+ NSMutableSet *added;
+ NSMutableSet *modified;
+ NSMutableSet *removed;
+ BOOL loaded;
+}
+- (NSDictionary*) contents;
+- (void) empty;
- (id) initWithName: (NSString*)n
owner: (NSUserDefaults*)o;
- (NSString*) name;
-- (void) setContents: (NSDictionary*)domain;
+- (id) objectForKey: (NSString*)aKey;
+- (BOOL) setObject: (id)anObject forKey: (NSString*)aKey;
+- (BOOL) setContents: (NSDictionary*)domain;
- (BOOL) synchronize;
-- (NSDate*) updated;
@end
static NSString *
@@ -1373,7 +1377,7 @@
NSDictionary *td;
pd = (*pImp)(_persDomains, objectForKeySel, dN);
- if (pd != nil && (object = [pd->contents objectForKey: defaultName]))
+ if (pd != nil && (object = [pd objectForKey: defaultName]))
break;
td = (*tImp)(_tempDomains, objectForKeySel, dN);
if (td != nil && (object = [td objectForKey: defaultName]))
@@ -1400,12 +1404,8 @@
if (nil != pd)
{
- id obj = [pd->contents objectForKey: defaultName];
-
- if (nil != obj)
+ if ([pd setObject: nil forKey: defaultName])
{
- pd->modified = YES;
- [pd->contents removeObjectForKey: defaultName];
[self _changePersistentDomain: processName];
}
}
@@ -1540,9 +1540,10 @@
[_persDomains setObject: pd forKey: processName];
[pd release];
}
- pd->modified = YES;
- [pd->contents setObject: value forKey: defaultName];
- [self _changePersistentDomain: processName];
+ if ([pd setObject: value forKey: defaultName])
+ {
+ [self _changePersistentDomain: processName];
+ }
[_lock unlock];
}
NS_HANDLER
@@ -1690,14 +1691,8 @@
pd = [_persDomains objectForKey: domainName];
if (nil != pd)
{
- if (YES == [domainName isEqualToString: NSGlobalDomain])
- {
- /* Don't remove the global domain, just its contents.
- */
- [pd->contents removeAllObjects];
- pd->modified = YES;
- }
- else
+ [pd empty];
+ if (NO == [domainName isEqualToString: NSGlobalDomain])
{
/* Remove the domain entirely.
*/
@@ -2054,7 +2049,7 @@
pd = (*pImp)(_persDomains, objectForKeySel, obj);
if (nil != pd)
{
- dict = pd->contents;
+ dict = [pd contents];
}
else
{
@@ -2477,9 +2472,9 @@
@implementation GSPersistentDomain
-- (NSMutableDictionary*) contents
-{
- if (nil == updated)
+- (NSDictionary*) contents
+{
+ if (NO == loaded)
{
[self synchronize];
}
@@ -2488,10 +2483,33 @@
- (void) dealloc
{
+ DESTROY(added);
+ DESTROY(removed);
+ DESTROY(modified);
DESTROY(contents);
- DESTROY(updated);
DESTROY(name);
+ DESTROY(path);
[super dealloc];
+}
+
+- (void) empty
+{
+ if (NO == loaded)
+ {
+ [self synchronize];
+ }
+ if ([contents count] > 0)
+ {
+ NSEnumerator *e;
+ NSString *k;
+
+ e = [[contents allKeys] objectEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ [self setObject: nil forKey: k];
+ }
+ [self synchronize];
+ }
}
- (id) initWithName: (NSString*)n
@@ -2499,9 +2517,14 @@
{
if (nil != (self = [super init]))
{
+ owner = o; // Not retained
name = [n copy];
- owner = o; // Not retained
+ path = RETAIN([[[owner _directory] stringByAppendingPathComponent: name]
+ stringByAppendingPathExtension: @"plist"]);
contents = [NSMutableDictionary new];
+ added = [NSMutableSet new];
+ removed = [NSMutableSet new];
+ modified = [NSMutableSet new];
}
return self;
}
@@ -2511,113 +2534,216 @@
return name;
}
-- (void) setContents: (NSDictionary*)domain
-{
+- (id) objectForKey: (NSString*)aKey
+{
+ return [contents objectForKey: aKey];
+}
+
+- (BOOL) setContents: (NSDictionary*)domain
+{
+ BOOL changed = NO;
+
if (NO == [contents isEqual: domain])
{
- NSMutableDictionary *m = [domain mutableCopy];
-
- if (nil == m)
- {
- m = [NSMutableDictionary new];
- }
- [contents release];
- contents = m;
- updated = [NSDate new];
- modified = YES;
+ NSEnumerator *e;
+ NSString *k;
+
+ e = [[contents allKeys] objectEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ if ([domain objectForKey: k] == nil)
+ {
+ [self setObject: nil forKey: k];
+ }
+ }
+ e = [domain keyEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ [self setObject: [domain objectForKey: k] forKey: k];
+ }
+ changed = YES;
+ }
+ return changed;
+}
+
+- (BOOL) setObject: (id)anObject forKey: (NSString*)aKey
+{
+ if (nil == anObject)
+ {
+ if (nil == [contents objectForKey: aKey])
+ {
+ return NO;
+ }
+ if ([added member: aKey])
+ {
+ [added removeObject: aKey];
+ }
+ else if ([modified member: aKey])
+ {
+ [modified removeObject: aKey];
+ [removed addObject: aKey];
+ }
+ else
+ {
+ [removed addObject: aKey];
+ }
+ [contents removeObjectForKey: aKey];
+ return YES;
+ }
+ else
+ {
+ id old = [contents objectForKey: aKey];
+
+ if ([anObject isEqual: old])
+ {
+ return NO;
+ }
+ if ([removed member: aKey])
+ {
+ [modified addObject: aKey];
+ [removed removeObject: aKey];
+ }
+ else if (nil == [modified member: aKey] && nil == [added member: aKey])
+ {
+ if (nil == old)
+ {
+ [added addObject: aKey];
+ }
+ else
+ {
+ [modified addObject: aKey];
+ }
+ }
+ [contents setObject: anObject forKey: aKey];
+ return YES;
}
}
- (BOOL) synchronize
{
- BOOL wasLocked;
- BOOL hadChange = NO; // Have we read a change from disk?
-
- if (NO == [owner _lockDefaultsFile: &wasLocked])
- {
- hadChange = NO;
- wasLocked = NO;
- }
- else
- {
- NSString *path;
-
- path = [[[owner _directory] stringByAppendingPathComponent: name]
- stringByAppendingPathExtension: @"plist"];
-
- if (YES == modified && NO == [owner _readOnly])
- {
- NSDate *mod;
- BOOL result;
-
- mod = [NSDate date];
- if (0 == [contents count])
- {
- /* Remove empty defaults dictionary.
- */
- result = writeDictionary(nil, path);
- }
- else
- {
- /* Write dictionary to file.
- */
- result = writeDictionary(contents, path);
- }
- if (YES == result)
- {
- ASSIGN(updated, mod);
- modified = NO;
- }
- }
- else
- {
- NSFileManager *mgr = [NSFileManager defaultManager];
- NSDate *mod;
-
- /* If the database was modified since the last refresh
- * we need to read it.
- */
- mod = [[mgr fileAttributesAtPath: path traverseLink: YES]
- objectForKey: NSFileModificationDate];
- if (nil == updated
- || (nil != mod && [updated laterDate: mod] != updated))
- {
- ASSIGN(updated, mod);
- if (nil != updated)
- {
- NSData *data;
-
- data = [NSData dataWithContentsOfFile: path];
- if (nil != data)
- {
- id o;
-
- o = [NSPropertyListSerialization
- propertyListWithData: data
- options: NSPropertyListImmutable
- format: 0
- error: 0];
- if ([o isKindOfClass: [NSDictionary class]])
- {
- [contents release];
- contents = [o mutableCopy];
- }
- }
- }
- hadChange = YES;
- }
- }
- if (NO == wasLocked)
- {
- [owner _unlockDefaultsFile];
- }
- }
- return hadChange;
-}
-
-- (NSDate*) updated
-{
- return updated;
+ BOOL isLocked = NO;
+ BOOL wasLocked = NO;
+ BOOL shouldLock = NO;
+ BOOL defaultsChanged = NO;
+ BOOL hasLocalChanges = NO;
+
+ if ([removed count] || [added count] || [modified count])
+ {
+ hasLocalChanges = YES;
+ }
+ if (YES == hasLocalChanges && NO == [owner _readOnly])
+ {
+ shouldLock = YES;
+ }
+ if (YES == shouldLock && YES == [owner _lockDefaultsFile: &wasLocked])
+ {
+ isLocked = YES;
+ }
+ NS_DURING
+ {
+ NSFileManager *mgr;
+ NSMutableDictionary *disk;
+
+ mgr = [NSFileManager defaultManager];
+ disk = nil;
+ if (YES == [mgr isReadableFileAtPath: path])
+ {
+ NSData *data;
+
+ data = [NSData dataWithContentsOfFile: path];
+ if (nil != data)
+ {
+ id o;
+
+ o = [NSPropertyListSerialization
+ propertyListWithData: data
+ options: NSPropertyListImmutable
+ format: 0
+ error: 0];
+ if ([o isKindOfClass: [NSDictionary class]])
+ {
+ disk = AUTORELEASE([o mutableCopy]);
+ }
+ }
+ }
+ if (nil == disk)
+ {
+ disk = [NSMutableDictionary dictionary];
+ }
+ loaded = YES;
+
+ if (NO == [contents isEqual: disk])
+ {
+ defaultsChanged = YES;
+ if (YES == hasLocalChanges)
+ {
+ NSEnumerator *e;
+ NSString *k;
+
+ e = [removed objectEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ [disk removeObjectForKey: k];
+ }
+ e = [added objectEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ [disk setObject: [contents objectForKey: k] forKey: k];
+ }
+ e = [modified objectEnumerator];
+ while (nil != (k = [e nextObject]))
+ {
+ [disk setObject: [contents objectForKey: k] forKey: k];
+ }
+ }
+ ASSIGN(contents, disk);
+ }
+ if (YES == hasLocalChanges)
+ {
+ BOOL written = NO;
+
+ if (NO == [owner _readOnly])
+ {
+ if (YES == isLocked)
+ {
+ if (0 == [contents count])
+ {
+ /* Remove empty defaults dictionary.
+ */
+ written = writeDictionary(nil, path);
+ }
+ else
+ {
+ /* Write dictionary to file.
+ */
+ written = writeDictionary(contents, path);
+ }
+ }
+ }
+ if (YES == written)
+ {
+ [added removeAllObjects];
+ [removed removeAllObjects];
+ [modified removeAllObjects];
+ }
+ }
+ if (YES == isLocked && NO == wasLocked)
+ {
+ isLocked = NO;
+ [owner _unlockDefaultsFile];
+ }
+ }
+ NS_HANDLER
+ {
+ fprintf(stderr, "problem synchronising defaults domain '%s': %s\n",
+ [name UTF8String], [[localException description] UTF8String]);
+ if (YES == isLocked && NO == wasLocked)
+ {
+ [owner _unlockDefaultsFile];
+ }
+ }
+ NS_ENDHANDLER
+ return defaultsChanged;
}
@end
_______________________________________________
Gnustep-cvs mailing list
[email protected]
https://mail.gna.org/listinfo/gnustep-cvs