Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Least Frequently Used eviction strategy #328

Merged
merged 6 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion Source/PINCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,33 @@ PIN_SUBCLASSING_RESTRICTED
deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder
ttlCache:(BOOL)ttlCache NS_DESIGNATED_INITIALIZER;
ttlCache:(BOOL)ttlCache;

/**
Multiple instances with the same name are *not* allowed and can *not* safely
access the same data on disk. Also used to create the <diskCache>.
Initializer allows you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization for <diskCache>.
You must provide both serializer and deserializer, or opt-out to default implementation providing nil values.

@see name
@param name The name of the cache.
@param rootPath The path of the cache on disk.
@param serializer A block used to serialize object before writing to disk. If nil provided, default NSKeyedArchiver serialized will be used.
@param deserializer A block used to deserialize object read from disk. If nil provided, default NSKeyedUnarchiver serialized will be used.
@param keyEncoder A block used to encode key(filename). If nil provided, default url encoder will be used
@param keyDecoder A block used to decode key(filename). If nil provided, default url decoder will be used
@param ttlCache Whether or not the cache should behave as a TTL cache.
@param evictionStrategy How the cache decide to evict objects when over cost.
@result A new cache with the specified name.
*/
- (instancetype)initWithName:(nonnull NSString *)name
rootPath:(nonnull NSString *)rootPath
serializer:(nullable PINDiskCacheSerializerBlock)serializer
deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder
ttlCache:(BOOL)ttlCache
evictionStrategy:(PINCacheEvictionStrategy)evictionStrategy NS_DESIGNATED_INITIALIZER;

@end

Expand Down
19 changes: 17 additions & 2 deletions Source/PINCache.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,25 @@ - (instancetype)initWithName:(NSString *)name
return [self initWithName:name rootPath:rootPath serializer:serializer deserializer:deserializer keyEncoder:keyEncoder keyDecoder:keyDecoder ttlCache:NO];
}

- (instancetype)initWithName:(nonnull NSString *)name
rootPath:(nonnull NSString *)rootPath
serializer:(nullable PINDiskCacheSerializerBlock)serializer
deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder
ttlCache:(BOOL)ttlCache
{
return [self initWithName:name rootPath:rootPath serializer:serializer deserializer:deserializer keyEncoder:keyEncoder keyDecoder:keyDecoder ttlCache:ttlCache evictionStrategy:PINCacheEvictionStrategyLeastRecentlyUsed];
}

- (instancetype)initWithName:(NSString *)name
rootPath:(NSString *)rootPath
serializer:(PINDiskCacheSerializerBlock)serializer
deserializer:(PINDiskCacheDeserializerBlock)deserializer
keyEncoder:(PINDiskCacheKeyEncoderBlock)keyEncoder
keyDecoder:(PINDiskCacheKeyDecoderBlock)keyDecoder
ttlCache:(BOOL)ttlCache
evictionStrategy:(PINCacheEvictionStrategy)evictionStrategy
{
if (!name)
return nil;
Expand All @@ -72,8 +84,11 @@ - (instancetype)initWithName:(NSString *)name
keyEncoder:keyEncoder
keyDecoder:keyDecoder
operationQueue:_operationQueue
ttlCache:ttlCache];
_memoryCache = [[PINMemoryCache alloc] initWithName:_name operationQueue:_operationQueue ttlCache:ttlCache];
ttlCache:ttlCache
byteLimit:PINDiskCacheDefaultByteLimit
ageLimit:PINDiskCacheDefaultAgeLimit
evictionStrategy:evictionStrategy];
_memoryCache = [[PINMemoryCache alloc] initWithName:_name operationQueue:_operationQueue ttlCache:ttlCache evictionStrategy:evictionStrategy];
}
return self;
}
Expand Down
5 changes: 5 additions & 0 deletions Source/PINCaching.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ typedef void (^PINCacheObjectEnumerationBlock)(__kindof id<PINCaching> cache, NS
*/
typedef void (^PINCacheObjectContainmentBlock)(BOOL containsObject);

typedef NS_ENUM(NSInteger, PINCacheEvictionStrategy) {
PINCacheEvictionStrategyLeastRecentlyUsed,
PINCacheEvictionStrategyLeastFrequentlyUsed,
};

@protocol PINCaching <NSObject>

#pragma mark - Core
Expand Down
51 changes: 45 additions & 6 deletions Source/PINDiskCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ extern NSErrorUserInfoKey const PINDiskCacheErrorReadFailureCodeKey;
extern NSErrorUserInfoKey const PINDiskCacheErrorWriteFailureCodeKey;
extern NSString * const PINDiskCachePrefix;

extern NSUInteger PINDiskCacheDefaultByteLimit;
extern NSTimeInterval PINDiskCacheDefaultAgeLimit;

typedef NS_ENUM(NSInteger, PINDiskCacheError) {
PINDiskCacheErrorReadFailure = -1000,
PINDiskCacheErrorWriteFailure = -1001,
Expand Down Expand Up @@ -168,6 +171,11 @@ PIN_SUBCLASSING_RESTRICTED
*/
@property (assign) NSTimeInterval ageLimit;

/**
The eviction strategy when trimming the cache.
*/
@property (atomic, assign) PINCacheEvictionStrategy evictionStrategy;

/**
The writing protection option used when writing a file on disk. This value is used every time an object is set.
NSDataWritingAtomic and NSDataWritingWithoutOverwriting are ignored if set
Expand Down Expand Up @@ -336,6 +344,33 @@ PIN_SUBCLASSING_RESTRICTED
operationQueue:(nonnull PINOperationQueue *)operationQueue
ttlCache:(BOOL)ttlCache;

/**
@see name
@param name The name of the cache.
@param prefix The prefix for the cache name. Defaults to com.pinterest.PINDiskCache
@param rootPath The path of the cache.
@param serializer A block used to serialize object. If nil provided, default NSKeyedArchiver serialized will be used.
@param deserializer A block used to deserialize object. If nil provided, default NSKeyedUnarchiver serialized will be used.
@param keyEncoder A block used to encode key(filename). If nil provided, default url encoder will be used
@param keyDecoder A block used to decode key(filename). If nil provided, default url decoder will be used
@param operationQueue A PINOperationQueue to run asynchronous operations
@param ttlCache Whether or not the cache should behave as a TTL cache.
@param byteLimit The maximum number of bytes allowed on disk. Defaults to 50MB.
@param ageLimit The maximum number of seconds an object is allowed to exist in the cache. Defaults to 30 days.
@result A new cache with the specified name.
*/
- (instancetype)initWithName:(nonnull NSString *)name
prefix:(nonnull NSString *)prefix
rootPath:(nonnull NSString *)rootPath
serializer:(nullable PINDiskCacheSerializerBlock)serializer
deserializer:(nullable PINDiskCacheDeserializerBlock)deserializer
keyEncoder:(nullable PINDiskCacheKeyEncoderBlock)keyEncoder
keyDecoder:(nullable PINDiskCacheKeyDecoderBlock)keyDecoder
operationQueue:(nonnull PINOperationQueue *)operationQueue
ttlCache:(BOOL)ttlCache
byteLimit:(NSUInteger)byteLimit
ageLimit:(NSTimeInterval)ageLimit;

/**
The designated initializer allowing you to override default NSKeyedArchiver/NSKeyedUnarchiver serialization.

Expand All @@ -351,6 +386,7 @@ PIN_SUBCLASSING_RESTRICTED
@param ttlCache Whether or not the cache should behave as a TTL cache.
@param byteLimit The maximum number of bytes allowed on disk. Defaults to 50MB.
@param ageLimit The maximum number of seconds an object is allowed to exist in the cache. Defaults to 30 days.
@param evictionStrategy How the cache decides to evict objects
@result A new cache with the specified name.
*/
- (instancetype)initWithName:(nonnull NSString *)name
Expand All @@ -363,7 +399,8 @@ PIN_SUBCLASSING_RESTRICTED
operationQueue:(nonnull PINOperationQueue *)operationQueue
ttlCache:(BOOL)ttlCache
byteLimit:(NSUInteger)byteLimit
ageLimit:(NSTimeInterval)ageLimit NS_DESIGNATED_INITIALIZER;
ageLimit:(NSTimeInterval)ageLimit
evictionStrategy:(PINCacheEvictionStrategy)evictionStrategy NS_DESIGNATED_INITIALIZER;

#pragma mark - Asynchronous Methods
/// @name Asynchronous Methods
Expand Down Expand Up @@ -471,7 +508,7 @@ PIN_SUBCLASSING_RESTRICTED
- (void)trimToSizeAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block;

/**
Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or smaller
Removes objects from the cache, using the eviction strategy, until the cache is equal to or smaller
than the specified byteCount. This method returns immediately and executes the passed block as soon as the cache has
been trimmed.

Expand All @@ -480,7 +517,7 @@ PIN_SUBCLASSING_RESTRICTED

@note This will not remove objects that have been added via one of the @c -setObject:forKey:withAgeLimit methods.
*/
- (void)trimToSizeByDateAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block;
- (void)trimToSizeByEvictionStrategyAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block;

/**
Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
Expand Down Expand Up @@ -564,15 +601,15 @@ PIN_SUBCLASSING_RESTRICTED
- (void)trimToSize:(NSUInteger)byteCount;

/**
Removes objects from the cache, ordered by date (least recently used first), until the cache is equal to or
Removes objects from the cache, using the defined evictionStrategy, until the cache is equal to or
smaller than the specified byteCount. This method blocks the calling thread until the cache has been trimmed.

@see trimToSizeByDateAsync:
@see trimToSizeByEvictionStrategyAsync:
@param byteCount The cache will be trimmed equal to or smaller than this size.

@note This will not remove objects that have been added via one of the @c -setObject:forKey:withAgeLimit methods.
*/
- (void)trimToSizeByDate:(NSUInteger)byteCount;
- (void)trimToSizeByEvictionStrategy:(NSUInteger)byteCount;

/**
Loops through all objects in the cache (reads and writes are suspended during the enumeration). Data is not actually
Expand Down Expand Up @@ -616,6 +653,8 @@ typedef void (^PINDiskCacheBlock)(PINDiskCache *cache);
- (void)removeAllObjects:(nullable PINDiskCacheBlock)block __attribute__((deprecated));
- (void)enumerateObjectsWithBlock:(PINDiskCacheFileURLBlock)block completionBlock:(nullable PINDiskCacheBlock)completionBlock __attribute__((deprecated));
- (void)setTtlCache:(BOOL)ttlCache DEPRECATED_MSG_ATTRIBUTE("ttlCache is no longer a settable property and must now be set via initializer.");
- (void)trimToSizeByDate:(NSUInteger)byteCount DEPRECATED_MSG_ATTRIBUTE("Use trimToSizeByEvictionStrategy: instead");
- (void)trimToSizeByDateAsync:(NSUInteger)byteCount completion:(nullable PINCacheBlock)block DEPRECATED_MSG_ATTRIBUTE("Use trimToSizeByEvictionStrategyAsync:completion: instead");
@end

NS_ASSUME_NONNULL_END
Loading
Loading