From c8a0d6738c61ad19ff0fc562e07b62ac3c40d690 Mon Sep 17 00:00:00 2001 From: appleguy Date: Thu, 21 Sep 2017 13:59:02 -0700 Subject: [PATCH] [PINDiskCache] Respect small byteLimit settings by checking object size in setObject: (#198) * [PINDiskCache] Respect small byteLimit settings by checking object size in setObject: This serves as a mechanism for some clients, like users of the Texture framework, to effectively disable the PINDiskCache by setting a byteLimit of 1. Before this change, the cache would transiently exceed the byte limit by writing the file anyway, and then immediately deleting it. This change will not affect most users of PINDiskCache, but is important for this specific use case. * [PINDiskCache] Fast-path objectForKey: when the cache is empty. * Fill out changelog * Ensure lock is acquired before early return in read path; fix test. --- CHANGELOG.md | 1 + Source/PINDiskCache.m | 31 ++++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2356eb8e..f7cca1dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Add your own contributions to the next release on the line below this with your name. ## 3.0.1 -- Beta 5 +- [fix] Respect small byteLimit settings by checking object size in setObject: [#198](https://github.com/pinterest/PINCache/pull/198) - [new] Added an ability to set custom encoder/decoder for file names: [#192](https://github.com/pinterest/PINCache/pull/192) ## 2.2.1 -- 2016 Mar 5 diff --git a/Source/PINDiskCache.m b/Source/PINDiskCache.m index 9427c489..5070ff7f 100644 --- a/Source/PINDiskCache.m +++ b/Source/PINDiskCache.m @@ -838,7 +838,11 @@ - (id)objectForKeyedSubscript:(NSString *)key { NSDate *now = [[NSDate alloc] init]; - if (!key) + [self lock]; + BOOL isEmpty = (_dates.count == 0 && _sizes.count == 0); + [self unlock]; + + if (!key || isEmpty) return nil; id object = nil; @@ -936,8 +940,23 @@ - (void)setObject:(id )object forKey:(NSString *)key fileURL:(NSURL ** NSDataWritingOptions writeOptions = NSDataWritingAtomic; #endif - NSURL *fileURL = [self encodedFileURLForKey:key]; - + // Remain unlocked here so that we're not locked while serializing. + NSData *data = _serializer(object, key); + NSURL *fileURL = nil; + + NSUInteger byteLimit = self.byteLimit; + if (data.length <= byteLimit || byteLimit == 0) { + // The cache is large enough to fit this object (although we may need to evict others). + fileURL = [self encodedFileURLForKey:key]; + } else { + // The cache isn't large enough to fit this object (even if all others were evicted). + // We should not write it to disk because it will be deleted immediately after. + if (outFileURL) { + *outFileURL = nil; + } + return; + } + [self lock]; PINCacheObjectBlock willAddObjectBlock = self->_willAddObjectBlock; if (willAddObjectBlock) { @@ -946,13 +965,7 @@ - (void)setObject:(id )object forKey:(NSString *)key fileURL:(NSURL ** [self lock]; } - //We unlock here so that we're not locked while serializing. - [self unlock]; - NSData *data = _serializer(object, key); - [self lock]; - NSError *writeError = nil; - BOOL written = [data writeToURL:fileURL options:writeOptions error:&writeError]; PINDiskCacheError(writeError);