Skip to content

Commit

Permalink
Adds support for dynamic caches to image pipeline
Browse files Browse the repository at this point in the history
Reviewed By: oprisnik

Differential Revision: D58132712

fbshipit-source-id: 3fe68754b7ac2ec50ba868fd7ba21d6a48933586
  • Loading branch information
Veeren Mandalia authored and facebook-github-bot committed Jun 5, 2024
1 parent f007e8e commit affc542
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ImagePipeline(
encodedMemoryCache: MemoryCache<CacheKey, PooledByteBuffer>,
mainBufferedDiskCache: BufferedDiskCache,
smallImageBufferedDiskCache: BufferedDiskCache,
dynamicBufferedDiskCaches: Map<String, BufferedDiskCache>?,
cacheKeyFactory: CacheKeyFactory,
threadHandoffProducerQueue: ThreadHandoffProducerQueue,
suppressBitmapPrefetchingSupplier: Supplier<Boolean>,
Expand All @@ -71,6 +72,7 @@ class ImagePipeline(
private val encodedMemoryCache: MemoryCache<CacheKey, PooledByteBuffer>
private val mainBufferedDiskCache: BufferedDiskCache
private val smallImageBufferedDiskCache: BufferedDiskCache
private var dynamicBufferedDiskCaches: Map<String, BufferedDiskCache>?

/** @return The CacheKeyFactory implementation used by ImagePipeline */
val cacheKeyFactory: CacheKeyFactory
Expand Down Expand Up @@ -606,6 +608,7 @@ class ImagePipeline(
val cacheKey = cacheKeyFactory.getEncodedCacheKey(imageRequest, null)
mainBufferedDiskCache.remove(cacheKey)
smallImageBufferedDiskCache.remove(cacheKey)
dynamicBufferedDiskCaches?.forEach { it.value.remove(cacheKey) }
}

/**
Expand All @@ -632,6 +635,7 @@ class ImagePipeline(
fun clearDiskCaches() {
mainBufferedDiskCache.clearAll()
smallImageBufferedDiskCache.clearAll()
dynamicBufferedDiskCaches?.forEach { it.value.clearAll() }
}

val usedDiskCacheSize: Long
Expand All @@ -640,7 +644,10 @@ class ImagePipeline(
*
* @return size in Bytes
*/
get() = mainBufferedDiskCache.size + smallImageBufferedDiskCache.size
get() =
mainBufferedDiskCache.size +
smallImageBufferedDiskCache.size +
(dynamicBufferedDiskCaches?.values?.sumOf { it.size } ?: 0)

/** Clear all the caches (memory and disk) */
fun clearCaches() {
Expand Down Expand Up @@ -1025,6 +1032,7 @@ class ImagePipeline(
this.encodedMemoryCache = encodedMemoryCache
this.mainBufferedDiskCache = mainBufferedDiskCache
this.smallImageBufferedDiskCache = smallImageBufferedDiskCache
this.dynamicBufferedDiskCaches = dynamicBufferedDiskCaches
this.cacheKeyFactory = cacheKeyFactory
this.threadHandoffProducerQueue = threadHandoffProducerQueue
this.suppressBitmapPrefetchingSupplier = suppressBitmapPrefetchingSupplier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ public static synchronized void shutDown() {
@Nullable private ProducerSequenceFactory mProducerSequenceFactory;
@Nullable private BufferedDiskCache mSmallImageBufferedDiskCache;
@Nullable private FileCache mSmallImageFileCache;

@Nullable private Map<String, FileCache> mDynamicFileCaches;
@Nullable private ImmutableMap<String, BufferedDiskCache> mDynamicBufferedDiskCaches;

Expand Down Expand Up @@ -350,6 +349,7 @@ private ImagePipeline createImagePipeline() {
getEncodedMemoryCache(),
getMainBufferedDiskCache(),
getSmallImageBufferedDiskCache(),
getDynamicBufferedDiskCaches(),
mConfig.getCacheKeyFactory(),
mThreadHandoffProducerQueue,
mConfig.getExperiments().getSuppressBitmapPrefetchingSupplier(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
import com.facebook.imagepipeline.producers.ThreadHandoffProducerQueue;
import com.facebook.imagepipeline.request.ImageRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -72,6 +74,8 @@ public class ImagePipelineTest {
private MemoryCache<CacheKey, PooledByteBuffer> mEncodedMemoryCache;
private BufferedDiskCache mMainDiskStorageCache;
private BufferedDiskCache mSmallImageDiskStorageCache;
private BufferedDiskCache mDynamicBufferedDiskCache;
private Map<String, BufferedDiskCache> mDynamicBufferedDiskCaches;
private RequestListener mRequestListener1;
private RequestListener mRequestListener2;
private ThreadHandoffProducerQueue mThreadHandoffProducerQueue;
Expand All @@ -91,6 +95,9 @@ public void setUp() throws Exception {
mEncodedMemoryCache = mock(MemoryCache.class);
mMainDiskStorageCache = mock(BufferedDiskCache.class);
mSmallImageDiskStorageCache = mock(BufferedDiskCache.class);
mDynamicBufferedDiskCache = mock(BufferedDiskCache.class);
mDynamicBufferedDiskCaches = new HashMap<>();
mDynamicBufferedDiskCaches.put("dynamicId1", mDynamicBufferedDiskCache);
mThreadHandoffProducerQueue = mock(ThreadHandoffProducerQueue.class);
mImagePipeline =
new ImagePipeline(
Expand All @@ -102,6 +109,7 @@ public void setUp() throws Exception {
mEncodedMemoryCache,
mMainDiskStorageCache,
mSmallImageDiskStorageCache,
mDynamicBufferedDiskCaches,
mCacheKeyFactory,
mThreadHandoffProducerQueue,
mSuppressBitmapPrefetchingSupplier,
Expand Down Expand Up @@ -468,6 +476,7 @@ public void testEvictFromDiskCache() {
mImagePipeline.evictFromDiskCache(uri);
verify(mMainDiskStorageCache).remove(multiKey);
verify(mSmallImageDiskStorageCache).remove(multiKey);
verify(mDynamicBufferedDiskCache).remove(multiKey);
}

@Test
Expand Down Expand Up @@ -526,13 +535,15 @@ public void testClearDiskCaches() {
mImagePipeline.clearDiskCaches();
verify(mMainDiskStorageCache).clearAll();
verify(mSmallImageDiskStorageCache).clearAll();
verify(mDynamicBufferedDiskCache).clearAll();
}

@Test
public void testDiskCachesSize() {
mImagePipeline.getUsedDiskCacheSize();
verify(mMainDiskStorageCache).getSize();
verify(mSmallImageDiskStorageCache).getSize();
verify(mDynamicBufferedDiskCache).getSize();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class ImagePipelineUtilsImpl(private val imageDecodeOptionsProvider: ImageDecode
if (imageOptions.cacheChoice != null) {
builder.cacheChoice = imageOptions.cacheChoice
}
if (imageOptions.diskCacheId != null) {
builder.diskCacheId = imageOptions.diskCacheId
}
return builder
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,23 @@ open class DecodedImageOptions(builder: Builder<*>) : EncodedImageOptions(builde

constructor() : super()

constructor(defaultOptions: ImageOptions) : super(defaultOptions) {
resizeOptions = defaultOptions.resizeOptions
rotationOptions = defaultOptions.rotationOptions
postprocessor = defaultOptions.postprocessor
imageDecodeOptions = defaultOptions.imageDecodeOptions
roundingOptions = defaultOptions.roundingOptions
borderOptions = defaultOptions.borderOptions
actualImageScaleType = defaultOptions.actualImageScaleType
actualFocusPoint = defaultOptions.actualImageFocusPoint
localThumbnailPreviewsEnabled = defaultOptions.areLocalThumbnailPreviewsEnabled()
loadThumbnailOnly = defaultOptions.loadThumbnailOnly
bitmapConfig = defaultOptions.bitmapConfig
progressiveDecodingEnabled = defaultOptions.isProgressiveDecodingEnabled
constructor(decodedImageOptions: DecodedImageOptions) : super(decodedImageOptions) {
resizeOptions = decodedImageOptions.resizeOptions
rotationOptions = decodedImageOptions.rotationOptions
postprocessor = decodedImageOptions.postprocessor
imageDecodeOptions = decodedImageOptions.imageDecodeOptions
roundingOptions = decodedImageOptions.roundingOptions
borderOptions = decodedImageOptions.borderOptions
actualImageScaleType = decodedImageOptions.actualImageScaleType
actualFocusPoint = decodedImageOptions.actualImageFocusPoint
localThumbnailPreviewsEnabled = decodedImageOptions.areLocalThumbnailPreviewsEnabled()
loadThumbnailOnly = decodedImageOptions.loadThumbnailOnly
bitmapConfig = decodedImageOptions.bitmapConfig
progressiveDecodingEnabled = decodedImageOptions.isProgressiveDecodingEnabled
}

constructor(defaultOptions: ImageOptions) : this(defaultOptions as DecodedImageOptions)

fun resize(resizeOptions: ResizeOptions?): T = modify { this.resizeOptions = resizeOptions }

fun rotate(rotationOptions: RotationOptions?): T = modify {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,23 @@ package com.facebook.fresco.vito.options
import com.facebook.common.internal.Objects
import com.facebook.imagepipeline.common.Priority
import com.facebook.imagepipeline.request.ImageRequest.CacheChoice
import com.facebook.imagepipeline.request.ImageRequestBuilder.BuilderException

open class EncodedImageOptions(builder: Builder<*>) {
val priority: Priority? = builder.priority
val cacheChoice: CacheChoice? = builder.cacheChoice
val diskCacheId: String? = builder.diskCacheId

init {
if (builder.cacheChoice == CacheChoice.DYNAMIC) {
if (diskCacheId == null) {
throw BuilderException("Disk cache id must be set for dynamic cache choice")
}
} else if (!diskCacheId.isNullOrEmpty()) {
throw BuilderException(
"Ensure that if you want to use a disk cache id, you set the CacheChoice to DYNAMIC")
}
}

override fun equals(other: Any?): Boolean {
if (this === other) {
Expand All @@ -26,34 +39,45 @@ open class EncodedImageOptions(builder: Builder<*>) {
}

protected fun equalEncodedOptions(other: EncodedImageOptions): Boolean {
return Objects.equal(priority, other.priority) && Objects.equal(cacheChoice, other.cacheChoice)
return Objects.equal(priority, other.priority) &&
Objects.equal(cacheChoice, other.cacheChoice) &&
Objects.equal(diskCacheId, other.diskCacheId)
}

override fun hashCode(): Int {
val result = priority?.hashCode() ?: 0
return 31 * result + (cacheChoice?.hashCode() ?: 0)
var result = priority?.hashCode() ?: 0
result = 31 * result + (cacheChoice?.hashCode() ?: 0)
result = 31 * result + (diskCacheId?.hashCode() ?: 0)
return result
}

override fun toString(): String = toStringHelper().toString()

protected open fun toStringHelper(): Objects.ToStringHelper =
Objects.toStringHelper(this).add("priority", priority).add("cacheChoice", cacheChoice)
Objects.toStringHelper(this)
.add("priority", priority)
.add("cacheChoice", cacheChoice)
.add("diskCacheId", diskCacheId)

open class Builder<T : Builder<T>> {
internal var priority: Priority? = null
internal var cacheChoice: CacheChoice? = null
internal var diskCacheId: String? = null

protected constructor()

protected constructor(defaultOptions: EncodedImageOptions) {
priority = defaultOptions.priority
cacheChoice = defaultOptions.cacheChoice
diskCacheId = defaultOptions.diskCacheId
}

fun priority(priority: Priority?): T = modify { this.priority = priority }

fun cacheChoice(cacheChoice: CacheChoice?): T = modify { this.cacheChoice = cacheChoice }

fun diskCacheId(diskCacheId: String?): T = modify { this.diskCacheId = diskCacheId }

open fun build(): EncodedImageOptions = EncodedImageOptions(this)

protected fun getThis(): T = this as T
Expand Down

0 comments on commit affc542

Please sign in to comment.