34#define PROFILE_WRITES 0
39#define CACHE_PLIST_FORMAT NSPropertyListBinaryFormat_v1_0
41#define CACHE_PLIST_FORMAT NSPropertyListGNUstepBinaryFormat
83@interface OOCacheManager (Private)
92- (BOOL)writeDict:(NSDictionary *)inDict;
94- (void)buildCachesFromDictionary:(NSDictionary *)inDict;
97- (BOOL)directoryExists:(NSString *)inPath create:(BOOL)inCreate;
102@interface OOCacheManager (PlatformSpecific)
104- (NSString *)cachePathCreatingIfNecessary:(BOOL)inCreate;
116- (id) initWithCacheContents:(NSDictionary *)cacheContents;
144- (NSString *)description
146 return [
NSString stringWithFormat:@"<%@ %p>{dirty=%s}", [
self class],
self, [
self dirty] ? "yes" : "no"];
162- (id)objectForKey:(NSString *)inKey inCache:(NSString *)inCacheKey
164 NSMutableDictionary *cache =
nil;
167 NSParameterAssert(inKey !=
nil && inCacheKey !=
nil);
169 cache = [_caches objectForKey:inCacheKey];
172 result = [
cache objectForKey:inKey];
192- (void)setObject:(
id)inObject forKey:(NSString *)inKey inCache:(NSString *)inCacheKey
194 NSMutableDictionary *cache =
nil;
196 NSParameterAssert(inObject !=
nil && inKey !=
nil && inCacheKey !=
nil);
200 cache = [_caches objectForKey:inCacheKey];
209 [_caches setObject:cache forKey:inCacheKey];
212 [
cache setObject:inObject forKey:inKey];
218- (void)removeObjectForKey:(NSString *)inKey inCache:(NSString *)inCacheKey
220 NSMutableDictionary *cache =
nil;
222 NSParameterAssert(inKey !=
nil && inCacheKey !=
nil);
224 cache = [_caches objectForKey:inCacheKey];
227 if (
nil != [cache objectForKey:inKey])
229 [
cache removeObjectForKey:inKey];
245- (void)clearCache:(NSString *)inCacheKey
247 NSParameterAssert(inCacheKey !=
nil);
251 [_caches removeObjectForKey:inCacheKey];
262- (void)clearAllCaches
270- (void) reloadAllCaches
287- (void)finishOngoingFlush
295- (void)setAllowCacheWrites:(BOOL)flag
301- (NSString *)cacheDirectoryPathCreatingIfNecessary:(BOOL)create
312 if (![
self directoryExists:cachePath create:create])
return nil;
316 [[
NSFileManager defaultManager] removeFileAtPath:[
cachePath stringByAppendingPathComponent:@"Oolite-cache.plist"] handler:nil];
319 cachePath = [
cachePath stringByAppendingPathComponent:@"org.aegidian.oolite"];
320 if (![
self directoryExists:cachePath create:create])
return nil;
327@implementation OOCacheManager (Private)
331 NSDictionary *cache =
nil;
332 NSString *cacheVersion =
nil;
333 NSString *ooliteVersion =
nil;
334 NSData *endianTag =
nil;
335 NSNumber *formatVersion =
nil;
337 uint64_t endianTagValue = 0;
339 ooliteVersion = [[[
NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
350 cacheVersion = [
cache objectForKey:kCacheKeyVersion];
351 if (![cacheVersion isEqual:ooliteVersion])
353 OOLog(
kOOLogDataCacheRebuild,
@"Data cache version (%@) does not match Oolite version (%@), rebuilding cache.", cacheVersion, ooliteVersion);
357 formatVersion = [
cache objectForKey:kCacheKeyFormatVersion];
366 endianTag = [
cache objectForKey:kCacheKeyEndianTag];
367 if (![endianTag isKindOfClass:[NSData
class]] || [endianTag length] !=
sizeof endianTagValue)
374 endianTagValue = *(
const uint64_t *)[endianTag bytes];
405 NSMutableDictionary *newCache =
nil;
406 NSString *ooliteVersion =
nil;
407 NSData *endianTag =
nil;
408 NSNumber *formatVersion =
nil;
409 NSDictionary *pListRep =
nil;
412 if (_caches ==
nil)
return;
413 if (_scheduledWrite !=
nil)
return;
420 OOLog(
@"dataCache.willWrite",
@"%@",
@"Scheduling data cache write.");
422 OOLog(
@"dataCache.willWrite",
@"%@",
@"About to write cache.");
425 ooliteVersion = [[[
NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
426 endianTag = [
NSData dataWithBytes:&endianTagValue length:sizeof endianTagValue];
427 formatVersion = [
NSNumber numberWithUnsignedInt:kFormatVersionValue];
430 if (ooliteVersion ==
nil || endianTag ==
nil || formatVersion ==
nil || pListRep ==
nil)
432 OOLog(
@"dataCache.cantWrite",
@"%@",
@"Failed to write data cache -- prerequisites not fulfilled. This is an internal error, please report it.");
437 [
newCache setObject:ooliteVersion forKey:kCacheKeyVersion];
438 [
newCache setObject:formatVersion forKey:kCacheKeyFormatVersion];
439 [
newCache setObject:endianTag forKey:kCacheKeyEndianTag];
440 [
newCache setObject:pListRep forKey:kCacheKeyCaches];
442#if PROFILE_WRITES && !WRITE_ASYNC
447 NSDictionary *cacheData = newCache;
452 OOLog(
@"dataCache.profile",
@"Time to prepare cache data: %g seconds.", endT);
458 OOLog(
@"dataCache.profile",
@"Time to prepare cache data: %g seconds.", prepareT);
461 if ([
self writeDict:newCache])
495 NSString *path =
nil;
497 NSString *errorString =
nil;
501 if (path ==
nil)
return nil;
505 data = [
NSData dataWithContentsOfFile:path];
506 if (data ==
nil)
return nil;
509 mutabilityOption:NSPropertyListImmutable
511 errorDescription:&errorString];
513 @catch (NSException *exception)
519 if (errorString !=
nil)
521 OOLog(
@"dataCache.badData",
@"Could not read data cache: %@", errorString);
522#if OOLITE_RELEASE_PLIST_ERROR_STRINGS
527 if (![contents isKindOfClass:[NSDictionary
class]])
return nil;
533- (BOOL)writeDict:(NSDictionary *)inDict
535 NSString *path =
nil;
537 NSString *errorDesc =
nil;
540 if (path ==
nil)
return NO;
549#if OOLITE_RELEASE_PLIST_ERROR_STRINGS
560 BOOL result = [
plist writeToFile:path atomically:NO];
565 OOLog(
@"dataCache.profile",
@"Time to serialize cache: %g seconds. Time to write data: %g seconds.", serializeT, writeT);
575- (void)buildCachesFromDictionary:(NSDictionary *)inDict
577 NSEnumerator *keyEnum =
nil;
580 NSMutableDictionary *cache =
nil;
582 if (inDict ==
nil )
return;
587 for (keyEnum = [inDict keyEnumerator]; (key = [
keyEnum nextObject]); )
589 value = [
inDict oo_dictionaryForKey:key];
595 [
_caches setObject:cache forKey:key];
604 return [OODeepCopy(_caches) autorelease];
608- (BOOL)directoryExists:(NSString *)inPath create:(BOOL)inCreate
610 BOOL exists, directory;
613 exists = [
fmgr fileExistsAtPath:inPath isDirectory:&directory];
615 if (exists && !directory)
622 if (!inCreate)
return NO;
623 if (![fmgr oo_createDirectoryAtPath:inPath attributes:
nil])
636- (NSString *)cachePathCreatingIfNecessary:(BOOL)create
639 return [
cachePath stringByAppendingPathComponent:@"Data Cache.plist"];
644- (NSString *)cachePathCreatingIfNecessary:(BOOL)create
646 NSString *cachePath = [
self cacheDirectoryPathCreatingIfNecessary:create];
647 return [cachePath stringByAppendingPathComponent:@"Oolite-cache.plist"];
655@implementation OOCacheManager (Singleton)
664+ (id)allocWithZone:(NSZone *)inZone
675- (id)copyWithZone:(NSZone *)inZone
687- (NSUInteger)retainCount
708- (id) initWithCacheContents:(NSDictionary *)cacheContents
710 if ((
self = [super init]))
732- (void) performAsyncTask
746- (void) completeAsyncTask
static NSString *const kCacheKeyEndianTag
static NSString *const kOOLogDataCacheWriteSuccess
static NSString *const kOOLogDataCacheBuildPathError
static NSString *const kOOLogDataCacheRetrieveSuccess
static NSString *const kOOLogDataCacheClearSuccess
static NSString *const kOOLogDataCacheWriteFailed
static NSString *const kOOLogDataCacheRetrieveFailed
static NSString *const kOOLogDataCacheSetFailed
static NSString *const kCacheKeyCaches
static NSString *const kOOLogDataCacheRebuild
static NSString *const kOOLogDataCacheSerializationError
static NSString *const kCacheKeyVersion
static NSString *const kOOLogDataCacheRemoveSuccess
static NSString *const kOOLogDataCacheNotFound
static NSString *const kCacheKeyFormatVersion
static NSString *const kOOLogDataCacheSetSuccess
static NSString *const kOOLogDataCacheFound
static OODebugMonitor * sSingleton
#define OODebugLog(class, format,...)
#define OOLogOutdentIf(class)
#define OOLog(class, format,...)
#define OOLogIndentIf(class)
NSDictionary * loadDict()
NSDictionary * dictionaryOfCaches()
NSDictionary * _cacheContents
BOOL addTask:priority:(id< OOAsyncWorkTask > task,[priority] OOAsyncWorkPriority priority)
void waitForTaskToComplete:(id< OOAsyncWorkTask > task)
OOAsyncWorkManager * sharedAsyncWorkManager()
NSMutableDictionary * _caches
void buildCachesFromDictionary:(NSDictionary *inDict)
NSString * cacheDirectoryPathCreatingIfNecessary:(BOOL create)
NSString * cachePathCreatingIfNecessary:(BOOL inCreate)
NSDictionary * loadDict()
NSDictionary * dictionaryOfCaches()