Added new logging component for Core Data cacheing subsystem. Fixed performance degradation in entity cache. Enabled RKManagedObjectCacheing callbacks to accelerate mapping, disabled processPendingChanges

This commit is contained in:
Blake Watters
2012-05-04 23:19:14 -04:00
parent fbcef6abd5
commit a01d47316c
7 changed files with 78 additions and 18 deletions

View File

@@ -17,7 +17,7 @@
// Set Logging Component
#undef RKLogComponent
#define RKLogComponent lcl_cRestKitCoreData
#define RKLogComponent lcl_cRestKitCoreDataCache
@interface RKEntityByAttributeCache ()
@property (nonatomic, retain) NSMutableDictionary *attributeValuesToObjectIDs;
@@ -68,6 +68,7 @@
[_attribute release];
[_managedObjectContext release];
[_attributeValuesToObjectIDs release];
[super dealloc];
}
@@ -83,6 +84,8 @@
- (BOOL)shouldCoerceAttributeToString:(NSString *)attributeValue
{
return NO;
if ([attributeValue isKindOfClass:[NSString class]] || [attributeValue isEqual:[NSNull null]]) {
return NO;
}
@@ -93,6 +96,7 @@
- (void)load
{
RKLogInfo(@"Loading entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:self.entity];
[fetchRequest setResultType:NSManagedObjectIDResultType];
@@ -106,7 +110,7 @@
[fetchRequest release];
self.attributeValuesToObjectIDs = [NSMutableDictionary dictionaryWithCapacity:[objectIDs count]];
for (NSManagedObjectID* objectID in objectIDs) {
for (NSManagedObjectID *objectID in objectIDs) {
NSError *error = nil;
NSManagedObject *object = [self.managedObjectContext existingObjectWithID:objectID error:&error];
if (! object && error) {
@@ -119,6 +123,7 @@
- (void)flush
{
RKLogInfo(@"Flushing entity cache for Entity '%@' by attribute '%@'", self.entity.name, self.attribute);
self.attributeValuesToObjectIDs = nil;
}
@@ -158,7 +163,7 @@
- (NSSet *)objectsWithAttributeValue:(id)attributeValue
{
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
if (set) {
NSSet *objectIDs = [NSSet setWithSet:set];
NSMutableSet *objects = [NSMutableSet setWithCapacity:[objectIDs count]];
@@ -181,8 +186,7 @@
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
if (attributeValue) {
NSManagedObjectID *objectID = [object objectID];
BOOL isTemporary = [objectID isTemporaryID];
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
if (set) {
[set addObject:objectID];
} else {
@@ -204,7 +208,7 @@
attributeValue = [self shouldCoerceAttributeToString:attributeValue] ? [attributeValue stringValue] : attributeValue;
if (attributeValue) {
NSManagedObjectID *objectID = [object objectID];
NSMutableSet *set = [self.attributeValuesToObjectIDs valueForKey:attributeValue];
NSMutableSet *set = [self.attributeValuesToObjectIDs objectForKey:attributeValue];
if (set) {
[set removeObject:objectID];
}

View File

@@ -39,10 +39,30 @@
}
}
static NSPredicate *predicate = nil;
// if (! predicate) {
predicate = [NSComparisonPredicate
predicateWithLeftExpression:[NSExpression expressionForKeyPath:primaryKeyAttribute]
rightExpression:[NSExpression expressionForConstantValue:searchValue]
modifier:NSDirectPredicateModifier
type:NSEqualToPredicateOperatorType
options:0];
// }
// [NSComparisonPredicate
// predicateWithLeftExpression:
// [NSExpression expressionForEvaluatedObject]
// rightExpression:
// [NSExpression expressionForConstantValue:objectForID]
// modifier:NSDirectPredicateModifier
// type:NSEqualToPredicateOperatorType
// options:0];
// [request setPredicate:predicate];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setFetchLimit:1];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, searchValue]];
[fetchRequest setPredicate:predicate];
// [fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, searchValue]];
NSArray *objects = [NSManagedObject executeFetchRequest:fetchRequest inContext:managedObjectContext];
RKLogDebug(@"Found objects '%@' using fetchRequest '%@'", objects, fetchRequest);
[fetchRequest release];

View File

@@ -7,6 +7,7 @@
//
#import "RKInMemoryManagedObjectCache.h"
#import "NSEntityDescription+RKAdditions.h"
#import "RKEntityCache.h"
#import "RKLog.h"
@@ -18,13 +19,9 @@ static NSString * const RKInMemoryObjectManagedObjectCacheThreadDictionaryKey =
@implementation RKInMemoryManagedObjectCache
- (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity
withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
value:(id)primaryKeyValue
inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext {
- (RKEntityCache *)cacheForEntity:(NSEntityDescription *)entity inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
NSAssert(entity, @"Cannot find existing managed object without a target class");
NSAssert(primaryKeyAttribute, @"Cannot find existing managed object instance without mapping");
NSAssert(primaryKeyValue, @"Cannot find existing managed object by primary key without a value");
NSAssert(managedObjectContext, @"Cannot find existing managed object with a context");
NSMutableDictionary *contextDictionary = [[[NSThread currentThread] threadDictionary] objectForKey:RKInMemoryObjectManagedObjectCacheThreadDictionaryKey];
if (! contextDictionary) {
@@ -40,14 +37,42 @@ static NSString * const RKInMemoryObjectManagedObjectCacheThreadDictionaryKey =
[entityCache release];
}
if (! [entityCache isEntity:entity cachedByAttribute:primaryKeyAttribute]) {
RKLogInfo(@"Cacheing instances of Entity '%@' by attribute '%@'", entity.name, primaryKeyAttribute);
[entityCache cacheObjectsForEntity:entity byAttribute:primaryKeyAttribute];
RKEntityByAttributeCache *attributeCache = [entityCache attributeCacheForEntity:entity attribute:primaryKeyAttribute];
if (! [entityCache isEntity:entity cachedByAttribute:entity.primaryKeyAttribute]) {
RKLogInfo(@"Cacheing instances of Entity '%@' by primary key attribute '%@'", entity.name, entity.primaryKeyAttribute);
[entityCache cacheObjectsForEntity:entity byAttribute:entity.primaryKeyAttribute];
RKEntityByAttributeCache *attributeCache = [entityCache attributeCacheForEntity:entity attribute:entity.primaryKeyAttribute];
RKLogTrace(@"Cached %d objects", [attributeCache count]);
}
return entityCache;
}
// TODO: This method signature needs to be cleaned up... Remove the primaryKeyAttribute being passed around.
- (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity
withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute
value:(id)primaryKeyValue
inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
RKEntityCache *entityCache = [self cacheForEntity:entity inManagedObjectContext:managedObjectContext];
return [entityCache objectForEntity:entity withAttribute:primaryKeyAttribute value:primaryKeyValue];
}
- (void)didFetchObject:(NSManagedObject *)object
{
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
[entityCache addObject:object];
}
- (void)didCreateObject:(NSManagedObject *)object
{
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
[entityCache addObject:object];
}
- (void)didDeleteObject:(NSManagedObject *)object
{
RKEntityCache *entityCache = [self cacheForEntity:object.entity inManagedObjectContext:object.managedObjectContext];
[entityCache removeObject:object];
}
@end

View File

@@ -170,11 +170,20 @@
if (primaryKeyAttribute && primaryKeyValue && NO == [primaryKeyValue isEqual:[NSNull null]]) {
object = [self.objectStore.cacheStrategy findInstanceOfEntity:entity
withPrimaryKeyAttribute:self.primaryKeyAttribute value:primaryKeyValue inManagedObjectContext:[self.objectStore managedObjectContextForCurrentThread]];
if (object && [self.objectStore.cacheStrategy respondsToSelector:@selector(didFetchObject:)]) {
[self.objectStore.cacheStrategy didFetchObject:object];
}
}
if (object == nil) {
object = [[[NSManagedObject alloc] initWithEntity:entity
insertIntoManagedObjectContext:[_objectStore managedObjectContextForCurrentThread]] autorelease];
[object setValue:primaryKeyValue forKey:primaryKeyAttribute];
if ([self.objectStore.cacheStrategy respondsToSelector:@selector(didCreateObject:)]) {
[self.objectStore.cacheStrategy didCreateObject:object];
}
}
return object;
}

View File

@@ -119,7 +119,7 @@
manually invoke processPendingChanges to prevent recreating objects with the same primary key.
See https://github.com/RestKit/RestKit/issues/661
*/
[[[(RKManagedObjectMapping *)self.objectMapping objectStore] managedObjectContextForCurrentThread] processPendingChanges];
// [[[(RKManagedObjectMapping *)self.objectMapping objectStore] managedObjectContextForCurrentThread] processPendingChanges];
[self connectRelationships];
}
return success;

View File

@@ -56,6 +56,7 @@ _lcl_component(RestKitNetworkQueue, "restkit.network.queue",
_lcl_component(RestKitNetworkReachability, "restkit.network.reachability", "RestKit/Network/Reachability")
_lcl_component(RestKitObjectMapping, "restkit.object_mapping", "RestKit/ObjectMapping")
_lcl_component(RestKitCoreData, "restkit.core_data", "RestKit/CoreData")
_lcl_component(RestKitCoreDataCache, "restkit.core_data.cache", "RestKit/CoreData/Cache")
_lcl_component(RestKitCoreDataSearchEngine, "restkit.core_data.search_engine", "RestKit/CoreData/SearchEngine")
_lcl_component(RestKitSupport, "restkit.support", "RestKit/Support")
_lcl_component(RestKitSupportParsers, "restkit.support.parsers", "RestKit/Support/Parsers")

View File

@@ -456,6 +456,7 @@
}
- (void)testMappingAPayloadContainingRepeatedObjectsPerformsAcceptablyWithInMemoryMappingCache {
RKLogConfigureByName("RestKit/CoreData/Cache", RKLogLevelTrace);
RKManagedObjectStore *store = [RKTestFactory managedObjectStore];
store.cacheStrategy = [RKInMemoryManagedObjectCache new];