From 792f1722c8679bf93c88b48addbe0cd668451faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Ekstr=C3=B6m?= Date: Tue, 14 Mar 2017 15:21:56 +0100 Subject: [PATCH] Expose `minimumFreeDiskSpaceFraction` Defaulting to require 10% of free disk space does not make sense for some apps. For example, on a huge disk, say 64GB, there is no reason to require 6GB free space for a 30MB cache. --- Sources/SPTPersistentCacheFileManager.m | 4 +-- Sources/SPTPersistentCacheOptions.m | 3 ++ Tests/SPTPersistentCacheFileManagerTests.m | 28 +++++++++++++++++++ .../SPTPersistentCacheOptions.h | 7 +++++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/Sources/SPTPersistentCacheFileManager.m b/Sources/SPTPersistentCacheFileManager.m index 61e8075..2e30742 100644 --- a/Sources/SPTPersistentCacheFileManager.m +++ b/Sources/SPTPersistentCacheFileManager.m @@ -22,8 +22,6 @@ #import "SPTPersistentCacheDebugUtilities.h" #import "SPTPersistentCacheOptions.h" -static const double SPTPersistentCacheFileManagerMinFreeDiskSpace = 0.1; - const NSUInteger SPTPersistentCacheFileManagerSubDirNameLength = 2; @implementation SPTPersistentCacheFileManager @@ -179,7 +177,7 @@ - (SPTPersistentCacheDiskSize)optimizedDiskSizeForCacheSize:(SPTPersistentCacheD SPTPersistentCacheDiskSize totalSpace = fileSystemSize.longLongValue; SPTPersistentCacheDiskSize freeSpace = fileSystemFreeSpace.longLongValue + currentCacheSize; SPTPersistentCacheDiskSize proposedCacheSize = freeSpace - llrint(totalSpace * - SPTPersistentCacheFileManagerMinFreeDiskSpace); + self.options.minimumFreeDiskSpaceFraction); tempCacheSize = MAX(0, proposedCacheSize); diff --git a/Sources/SPTPersistentCacheOptions.m b/Sources/SPTPersistentCacheOptions.m index 3ad5297..ce3c249 100644 --- a/Sources/SPTPersistentCacheOptions.m +++ b/Sources/SPTPersistentCacheOptions.m @@ -27,6 +27,7 @@ const NSUInteger SPTPersistentCacheDefaultExpirationTimeSec = 10 * 60; const NSUInteger SPTPersistentCacheDefaultGCIntervalSec = 6 * 60 + 3; const NSUInteger SPTPersistentCacheDefaultCacheSizeInBytes = 0; // unbounded +const double SPTPersistentCacheDefaultMinFreeDiskSpaceFraction = 0.1; // 10% of total disk size const NSUInteger SPTPersistentCacheMinimumGCIntervalLimit = 60; const NSUInteger SPTPersistentCacheMinimumExpirationLimit = 60; @@ -55,6 +56,7 @@ - (instancetype)init _garbageCollectionInterval = SPTPersistentCacheDefaultGCIntervalSec; _defaultExpirationPeriod = SPTPersistentCacheDefaultExpirationTimeSec; _sizeConstraintBytes = SPTPersistentCacheDefaultCacheSizeInBytes; + _minimumFreeDiskSpaceFraction = SPTPersistentCacheDefaultMinFreeDiskSpaceFraction; _maxConcurrentOperations = NSOperationQueueDefaultMaxConcurrentOperationCount; _writePriority = NSOperationQueuePriorityNormal; _writeQualityOfService = NSQualityOfServiceDefault; @@ -117,6 +119,7 @@ - (id)copyWithZone:(NSZone *)zone copy.garbageCollectionInterval = self.garbageCollectionInterval; copy.defaultExpirationPeriod = self.defaultExpirationPeriod; copy.sizeConstraintBytes = self.sizeConstraintBytes; + copy.minimumFreeDiskSpaceFraction = self.minimumFreeDiskSpaceFraction; copy.debugOutput = self.debugOutput; copy.timingCallback = self.timingCallback; diff --git a/Tests/SPTPersistentCacheFileManagerTests.m b/Tests/SPTPersistentCacheFileManagerTests.m index bdea950..78ef5fe 100644 --- a/Tests/SPTPersistentCacheFileManagerTests.m +++ b/Tests/SPTPersistentCacheFileManagerTests.m @@ -69,6 +69,7 @@ - (void)setUp SPTPersistentCacheOptions *options = [SPTPersistentCacheOptions new]; options.cachePath = SPTPersistentCacheFileManagerTestsCachePath; options.cacheIdentifier = @"test"; + options.sizeConstraintBytes = (SPTPersistentCacheDiskSize)1024 * 1024 * 1024 * 3; // 3 GiB self.options = options; self.cacheFileManager = [[SPTPersistentCacheFileManagerForTests alloc] initWithOptions:self.options]; @@ -168,6 +169,33 @@ - (void)testOptimizedDiskSizeForCacheSizeSmall XCTAssertEqual(optimizedSize, (SPTPersistentCacheDiskSize)0); } +- (void)testMinimumFreeDiskSpaceFraction +{ + const SPTPersistentCacheDiskSize diskSize = (SPTPersistentCacheDiskSize)1024 * 1024 * 1024 * 16; // 16GiB + const SPTPersistentCacheDiskSize freeSpace = (SPTPersistentCacheDiskSize)1024 * 1024 * 1024 * 8; // 8GiB + NSFileManagerMock *fileManager = [NSFileManagerMock new]; + fileManager.mock_attributesOfFileSystemForPaths = @{SPTPersistentCacheFileManagerTestsCachePath: @{NSFileSystemSize: @(diskSize), + NSFileSystemFreeSize: @(freeSpace)}}; + self.cacheFileManager.test_fileManager = fileManager; + + self.cacheFileManager.options.minimumFreeDiskSpaceFraction = 1.0; + SPTPersistentCacheDiskSize optimizedSize = [self.cacheFileManager optimizedDiskSizeForCacheSize:0]; + XCTAssertEqual(optimizedSize, (SPTPersistentCacheDiskSize)0); + + self.cacheFileManager.options.minimumFreeDiskSpaceFraction = 0.0; + optimizedSize = [self.cacheFileManager optimizedDiskSizeForCacheSize:0]; + XCTAssertEqual(optimizedSize, (SPTPersistentCacheDiskSize)self.options.sizeConstraintBytes); + + self.cacheFileManager.options.minimumFreeDiskSpaceFraction = 0.5; + optimizedSize = [self.cacheFileManager optimizedDiskSizeForCacheSize:0]; + XCTAssertEqual(optimizedSize, (SPTPersistentCacheDiskSize)0); + + const SPTPersistentCacheDiskSize twoGiB = (SPTPersistentCacheDiskSize)1024 * 1024 * 1024 * 2; + self.cacheFileManager.options.minimumFreeDiskSpaceFraction = (freeSpace - twoGiB) / (double)diskSize; + optimizedSize = [self.cacheFileManager optimizedDiskSizeForCacheSize:0]; + XCTAssertEqual(optimizedSize, twoGiB); +} + - (void)testRemoveAllDataButKeysWithoutKeys { NSString *keyOne = @"AA"; diff --git a/include/SPTPersistentCache/SPTPersistentCacheOptions.h b/include/SPTPersistentCache/SPTPersistentCacheOptions.h index 243caa6..b87cee1 100644 --- a/include/SPTPersistentCache/SPTPersistentCacheOptions.h +++ b/include/SPTPersistentCache/SPTPersistentCacheOptions.h @@ -178,6 +178,13 @@ FOUNDATION_EXPORT const NSUInteger SPTPersistentCacheMinimumExpirationLimit; * @note Defaults to `0` (unbounded). */ @property (nonatomic, assign) NSUInteger sizeConstraintBytes; +/** + * The minimum fraction of free disk space required for caching. If there is less disk space + * available than this, the cache will be purged during garbage collection until the treshold + * is met. This could mean that the whole cache is evicted if the device is low on space. + * @note Defaults to `0.1`, 10% of the total disk size. + */ +@property (nonatomic, assign) double minimumFreeDiskSpaceFraction; /** * The queue priority for garbage collection. Defaults to NSOperationQueuePriorityLow. */