Skip to content

Commit e1b2e91

Browse files
committed
Performance optimization for YapCache
1 parent 5ca9fb1 commit e1b2e91

File tree

6 files changed

+66
-30
lines changed

6 files changed

+66
-30
lines changed

Testing/Benchmarking/BenchmarkYapCache.m

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,14 @@ + (NSTimeInterval)testNSCache:(NSUInteger)cacheSize
103103
+ (NSTimeInterval)testYapCache:(NSUInteger)cacheSize
104104
{
105105
#if TEST_COLLECTION_KEY
106-
Class keyClass = [YapCollectionKey class];
106+
YapCache *cache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]
107+
keyCallbacks:[YapCollectionKey keyCallbacks]
108+
countLimit:cacheSize];
107109
#else
108-
Class keyClass = [NSString class];
110+
YapCache *cache = [[YapCache alloc] initWithKeyClass:[NSString class] countLimit:cacheSize];
109111
#endif
110112

111-
YapCache *cache = [[YapCache alloc] initWithKeyClass:keyClass countLimit:cacheSize];
113+
112114

113115
NSUInteger hitCount = 0;
114116

YapDatabase/Internal/YapCache.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828
* Initializes a cache.
2929
*
3030
* Since the countLimit is a common configuration, it may optionally be passed during initialization.
31-
* This is also used as a hint internally when initializing components (i.e. [NSMutableDictionary initWithCapacity:]).
3231
**/
3332
- (id)initWithKeyClass:(Class)keyClass;
3433
- (id)initWithKeyClass:(Class)keyClass countLimit:(NSUInteger)countLimit;
3534

35+
- (id)initWithKeyClass:(Class)keyClass
36+
keyCallbacks:(CFDictionaryKeyCallBacks)keyCallbacks
37+
countLimit:(NSUInteger)countLimit;
38+
3639
/**
3740
* The countLimit specifies the maximum number of items to keep in the cache.
3841
* This limit is strictly enforced.

YapDatabase/Internal/YapCache.m

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,28 @@ @implementation YapCache
8181

8282
- (id)init
8383
{
84-
return [self initWithKeyClass:NULL countLimit:0];
84+
return [self initWithKeyClass:NULL
85+
keyCallbacks:kCFTypeDictionaryKeyCallBacks
86+
countLimit:0];
8587
}
8688

8789
- (id)initWithKeyClass:(Class)inKeyClass
8890
{
89-
return [self initWithKeyClass:inKeyClass countLimit:0];
91+
return [self initWithKeyClass:inKeyClass
92+
keyCallbacks:kCFTypeDictionaryKeyCallBacks
93+
countLimit:0];
9094
}
9195

9296
- (id)initWithKeyClass:(Class)inKeyClass countLimit:(NSUInteger)inCountLimit
97+
{
98+
return [self initWithKeyClass:inKeyClass
99+
keyCallbacks:kCFTypeDictionaryKeyCallBacks
100+
countLimit:inCountLimit];
101+
}
102+
103+
- (id)initWithKeyClass:(Class)inKeyClass
104+
keyCallbacks:(CFDictionaryKeyCallBacks)inKeyCallbacks
105+
countLimit:(NSUInteger)inCountLimit
93106
{
94107
if ((self = [super init]))
95108
{
@@ -109,7 +122,7 @@ - (id)initWithKeyClass:(Class)inKeyClass countLimit:(NSUInteger)inCountLimit
109122

110123
cfdict = CFDictionaryCreateMutable(kCFAllocatorDefault,
111124
0,
112-
&kCFTypeDictionaryKeyCallBacks,
125+
&inKeyCallbacks,
113126
&kCFTypeDictionaryValueCallBacks);
114127
}
115128
return self;

YapDatabase/Utilities/YapCollectionKey.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
**/
1010
@interface YapCollectionKey : NSObject <NSCopying, NSCoding>
1111

12-
YapCollectionKey* YapCollectionKeyCreate(NSString *collection, NSString *key);
13-
1412
- (id)initWithCollection:(NSString *)collection key:(NSString *)key;
1513

1614
@property (nonatomic, strong, readonly) NSString *collection;
@@ -22,7 +20,14 @@ YapCollectionKey* YapCollectionKeyCreate(NSString *collection, NSString *key);
2220
- (BOOL)isEqual:(id)anObject;
2321
- (NSUInteger)hash;
2422

25-
// Super optimized:
26-
BOOL YapCollectionKeyEqual(__unsafe_unretained YapCollectionKey *ck1, __unsafe_unretained YapCollectionKey *ck2);
23+
// For optimizing usage in YapCache
24+
+ (CFDictionaryKeyCallBacks)keyCallbacks;
25+
26+
// Super optimized (c function call faster than obj-c method invocation):
27+
BOOL YapCollectionKeyEqual(const __unsafe_unretained YapCollectionKey *ck1,
28+
const __unsafe_unretained YapCollectionKey *ck2);
29+
30+
// Lazy programmer (less typing than alloc/init)
31+
YapCollectionKey* YapCollectionKeyCreate(NSString *collection, NSString *key);
2732

2833
@end

YapDatabase/Utilities/YapCollectionKey.m

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,6 @@ @implementation YapCollectionKey
140140
return [[YapCollectionKey alloc] initWithCollection:collection key:key];
141141
}
142142

143-
NS_INLINE NSUInteger YapCollectionKeyHash(YapCollectionKey *ck)
144-
{
145-
// We need a fast way to combine 2 hashes without creating a new string (which is slow).
146-
// To accomplish this we use the murmur hashing algorithm.
147-
148-
return YDB_MurmurHash([ck->collection hash], [ck->key hash]);
149-
}
150-
151143
@synthesize collection = collection;
152144
@synthesize key = key;
153145

@@ -165,7 +157,7 @@ - (id)initWithCollection:(NSString *)aCollection key:(NSString *)aKey
165157
else
166158
key = [aKey copy]; // copy == retain if aKey is immutable
167159

168-
hash = YapCollectionKeyHash(self);
160+
hash = YDB_MurmurHash([collection hash], [key hash]);
169161
}
170162
return self;
171163
}
@@ -177,7 +169,7 @@ - (id)initWithCoder:(NSCoder *)decoder
177169
collection = [decoder decodeObjectForKey:@"collection"];
178170
key = [decoder decodeObjectForKey:@"key"];
179171

180-
hash = YapCollectionKeyHash(self);
172+
hash = YDB_MurmurHash([collection hash], [key hash]);
181173
}
182174
return self;
183175
}
@@ -216,7 +208,8 @@ - (BOOL)isEqual:(id)obj
216208
return NO;
217209
}
218210

219-
BOOL YapCollectionKeyEqual(__unsafe_unretained YapCollectionKey *ck1, __unsafe_unretained YapCollectionKey *ck2)
211+
BOOL YapCollectionKeyEqual(const __unsafe_unretained YapCollectionKey *ck1,
212+
const __unsafe_unretained YapCollectionKey *ck2)
220213
{
221214
if (ck1->hash != ck2->hash)
222215
return NO;
@@ -229,9 +222,25 @@ - (NSUInteger)hash
229222
return hash;
230223
}
231224

225+
CFHashCode YapCollectionKeyHash(const __unsafe_unretained YapCollectionKey *ck)
226+
{
227+
return (CFHashCode)(ck->hash);
228+
}
229+
232230
- (NSString *)description
233231
{
234232
return [NSString stringWithFormat:@"<YapCollectionKey collection(%@) key(%@)>", collection, key];
235233
}
236234

235+
+ (CFDictionaryKeyCallBacks)keyCallbacks
236+
{
237+
CFDictionaryKeyCallBacks keyCallbacks;
238+
memcpy(&keyCallbacks, &kCFTypeDictionaryKeyCallBacks, sizeof(CFDictionaryKeyCallBacks));
239+
240+
keyCallbacks.equal = (CFDictionaryEqualCallBack)YapCollectionKeyEqual;
241+
keyCallbacks.hash = (CFDictionaryHashCallBack)YapCollectionKeyHash;
242+
243+
return keyCallbacks;
244+
}
245+
237246
@end

YapDatabase/YapDatabaseConnection.m

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,9 @@ - (id)initWithDatabase:(YapDatabase *)inDatabase
131131
if (defaults.objectCacheEnabled)
132132
{
133133
objectCacheLimit = defaults.objectCacheLimit;
134-
objectCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]];
135-
objectCache.countLimit = objectCacheLimit;
134+
objectCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]
135+
keyCallbacks:[YapCollectionKey keyCallbacks]
136+
countLimit:objectCacheLimit];
136137

137138
if (keyCacheLimit != UNLIMITED_CACHE_LIMIT)
138139
{
@@ -145,8 +146,9 @@ - (id)initWithDatabase:(YapDatabase *)inDatabase
145146
if (defaults.metadataCacheEnabled)
146147
{
147148
metadataCacheLimit = defaults.metadataCacheLimit;
148-
metadataCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]];
149-
metadataCache.countLimit = metadataCacheLimit;
149+
metadataCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]
150+
keyCallbacks:[YapCollectionKey keyCallbacks]
151+
countLimit:metadataCacheLimit];
150152

151153
if (keyCacheLimit != UNLIMITED_CACHE_LIMIT)
152154
{
@@ -456,8 +458,9 @@ - (void)setObjectCacheEnabled:(BOOL)flag
456458
{
457459
if (objectCache == nil)
458460
{
459-
objectCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]];
460-
objectCache.countLimit = objectCacheLimit;
461+
objectCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]
462+
keyCallbacks:[YapCollectionKey keyCallbacks]
463+
countLimit:objectCacheLimit];
461464
}
462465
}
463466
else // Disabled
@@ -540,8 +543,9 @@ - (void)setMetadataCacheEnabled:(BOOL)flag
540543
{
541544
if (metadataCache == nil)
542545
{
543-
metadataCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]];
544-
metadataCache.countLimit = metadataCacheLimit;
546+
metadataCache = [[YapCache alloc] initWithKeyClass:[YapCollectionKey class]
547+
keyCallbacks:[YapCollectionKey keyCallbacks]
548+
countLimit:metadataCacheLimit];
545549
}
546550
}
547551
else // Disabled

0 commit comments

Comments
 (0)