/// <summary>
 /// Instantiates the <see cref="ImagePipelineCore"/>.
 /// </summary>
 /// <param name="producerSequenceFactory">
 /// The factory that creates all producer sequences.
 /// </param>
 /// <param name="requestListeners">
 /// The listeners for the image requests.
 /// </param>
 /// <param name="isPrefetchEnabledSupplier">
 /// The supplier for enabling prefetch.
 /// </param>
 /// <param name="bitmapMemoryCache">
 /// The memory cache for CloseableImage.
 /// </param>
 /// <param name="encodedMemoryCache">
 /// The memory cache for IPooledByteBuffer.
 /// </param>
 /// <param name="mainBufferedDiskCache">
 /// The default buffered disk cache.
 /// </param>
 /// <param name="smallImageBufferedDiskCache">
 /// The buffered disk cache used for small images.
 /// </param>
 /// <param name="cacheKeyFactory">
 /// The factory that creates cache keys for the pipeline.
 /// </param>
 /// <param name="threadHandoffProducerQueue">
 /// Move further computation to different thread.
 /// </param>
 /// <param name="flexByteArrayPool">
 /// The memory pool use for BitmapImage conversion.
 /// </param>
 public ImagePipelineCore(
     ProducerSequenceFactory producerSequenceFactory,
     HashSet <IRequestListener> requestListeners,
     ISupplier <bool> isPrefetchEnabledSupplier,
     IMemoryCache <ICacheKey, CloseableImage> bitmapMemoryCache,
     IMemoryCache <ICacheKey, IPooledByteBuffer> encodedMemoryCache,
     BufferedDiskCache mainBufferedDiskCache,
     BufferedDiskCache smallImageBufferedDiskCache,
     ICacheKeyFactory cacheKeyFactory,
     ThreadHandoffProducerQueue threadHandoffProducerQueue,
     FlexByteArrayPool flexByteArrayPool)
 {
     _idCounter = 0;
     _producerSequenceFactory     = producerSequenceFactory;
     _requestListener             = new ForwardingRequestListener(requestListeners);
     _isPrefetchEnabledSupplier   = isPrefetchEnabledSupplier;
     _bitmapMemoryCache           = bitmapMemoryCache;
     _encodedMemoryCache          = encodedMemoryCache;
     _mainBufferedDiskCache       = mainBufferedDiskCache;
     _smallImageBufferedDiskCache = smallImageBufferedDiskCache;
     _cacheKeyFactory             = cacheKeyFactory;
     _threadHandoffProducerQueue  = threadHandoffProducerQueue;
     _flexByteArrayPool           = flexByteArrayPool;
     _handleResultExecutor        = Executors.NewFixedThreadPool(MAX_DATA_SOURCE_SUBSCRIBERS);
 }
 /// <summary>
 /// Instantiates the <see cref="DiskCacheProducer"/>.
 /// </summary>
 public DiskCacheProducer(
     BufferedDiskCache defaultBufferedDiskCache,
     BufferedDiskCache smallImageBufferedDiskCache,
     ICacheKeyFactory cacheKeyFactory,
     IProducer <EncodedImage> inputProducer,
     int forceSmallCacheThresholdBytes)
 {
     _defaultBufferedDiskCache    = defaultBufferedDiskCache;
     _smallImageBufferedDiskCache = smallImageBufferedDiskCache;
     _cacheKeyFactory             = cacheKeyFactory;
     _inputProducer = inputProducer;
     _forceSmallCacheThresholdBytes = forceSmallCacheThresholdBytes;
     _chooseCacheByImageSize        = (forceSmallCacheThresholdBytes > 0);
 }
Example #3
0
        public void Initialize()
        {
            // Initializes the IFileCache
            _fileCacheFactory = new DiskStorageCacheFactory(new DynamicDefaultDiskStorageFactory());
            _fileCache        = _fileCacheFactory.Get(DiskCacheConfig.NewBuilder().Build());

            // Initializes the IPooledByteBufferFactory and PooledByteStreams
            _poolFactory       = new PoolFactory(PoolConfig.NewBuilder().Build());
            _byteBufferFactory = _poolFactory.PooledByteBufferFactory;
            _pooledByteStreams = _poolFactory.PooledByteStreams;

            // Initializes the IPooledByteBuffer from an image
            var file = StorageFile.GetFileFromApplicationUriAsync(
                new Uri("ms-appx:///Assets/SplashScreen.scale-200.png")).GetAwaiter().GetResult();

            using (var stream = file.OpenReadAsync().GetAwaiter().GetResult())
            {
                _pooledByteBuffer = _byteBufferFactory.NewByteBuffer(
                    ByteStreams.ToByteArray(stream.AsStream()));
            }

            _closeableReference = CloseableReference <IPooledByteBuffer> .of(_pooledByteBuffer);

            _encodedImage           = new EncodedImage(_closeableReference);
            _stagingArea            = StagingArea.Instance;
            _imageCacheStatsTracker = NoOpImageCacheStatsTracker.Instance;

            // Initializes the cache keys
            IList <ICacheKey> keys = new List <ICacheKey>();

            keys.Add(new SimpleCacheKey("http://test.uri"));
            keys.Add(new SimpleCacheKey("http://tyrone.uri"));
            keys.Add(new SimpleCacheKey("http://ian.uri"));
            _cacheKey = new MultiCacheKey(keys);

            // Initializes the executors
            _isCancelled           = new AtomicBoolean(false);
            _readPriorityExecutor  = Executors.NewFixedThreadPool(1);
            _writePriorityExecutor = Executors.NewFixedThreadPool(1);

            // Initializes the disk cache
            _bufferedDiskCache = new BufferedDiskCache(
                _fileCache,
                _byteBufferFactory,
                _pooledByteStreams,
                _readPriorityExecutor,
                _writePriorityExecutor,
                _imageCacheStatsTracker);
        }
Example #4
0
        public async Task TestSyncDiskCacheCheck()
        {
            await _bufferedDiskCache.Put(_cacheKey, _encodedImage);

            _fileCache = _fileCacheFactory.Get(DiskCacheConfig.NewBuilder().Build());
            _stagingArea.ClearAll();
            _bufferedDiskCache = new BufferedDiskCache(
                _fileCache,
                _byteBufferFactory,
                _pooledByteStreams,
                _readPriorityExecutor,
                _writePriorityExecutor,
                _imageCacheStatsTracker);
            Assert.IsTrue(_bufferedDiskCache.DiskCheckSync(_cacheKey));
        }
Example #5
0
        private BufferedDiskCache GetSmallImageBufferedDiskCache()
        {
            if (_smallImageBufferedDiskCache == null)
            {
                _smallImageBufferedDiskCache =
                    new BufferedDiskCache(
                        GetSmallImageFileCache(),
                        _config.PoolFactory.PooledByteBufferFactory,
                        _config.PoolFactory.PooledByteStreams,
                        _config.ExecutorSupplier.ForLocalStorageRead,
                        _config.ExecutorSupplier.ForLocalStorageWrite,
                        _config.ImageCacheStatsTracker);
            }

            return(_smallImageBufferedDiskCache);
        }
 /// <summary>
 /// Instantiates the <see cref="DiskCacheConsumer"/>.
 /// </summary>
 internal DiskCacheConsumer(
     BufferedDiskCache defaultBufferedDiskCache,
     BufferedDiskCache smallImageBufferedDiskCache,
     bool chooseCacheByImageSize,
     int forceSmallCacheThresholdBytes,
     IConsumer <EncodedImage> consumer,
     BufferedDiskCache cache,
     ICacheKey cacheKey) :
     base(consumer)
 {
     _defaultBufferedDiskCache      = defaultBufferedDiskCache;
     _smallImageBufferedDiskCache   = smallImageBufferedDiskCache;
     _chooseCacheByImageSize        = chooseCacheByImageSize;
     _forceSmallCacheThresholdBytes = forceSmallCacheThresholdBytes;
     _cache    = cache;
     _cacheKey = cacheKey;
 }
Example #7
0
        /// <summary>
        /// Instantiates the <see cref="ProducerFactory"/>
        /// </summary>
        /// <param name="byteArrayPool">
        /// The IByteArrayPool used by DecodeProducer.
        /// </param>
        /// <param name="imageDecoder">
        /// The image decoder.
        /// </param>
        /// <param name="progressiveJpegConfig">
        /// The progressive Jpeg configuration.
        /// </param>
        /// <param name="downsampleEnabled">
        /// Enabling downsample.
        /// </param>
        /// <param name="resizeAndRotateEnabledForNetwork">
        /// Enabling resize and rotate.
        /// </param>
        /// <param name="executorSupplier">
        /// The supplier for tasks.
        /// </param>
        /// <param name="pooledByteBufferFactory">
        /// The factory that allocates IPooledByteBuffer memory.
        /// </param>
        /// <param name="bitmapMemoryCache">
        /// The memory cache for CloseableImage.
        /// </param>
        /// <param name="encodedMemoryCache">
        /// The memory cache for IPooledByteBuffer.
        /// </param>
        /// <param name="defaultBufferedDiskCache">
        /// The default buffered disk cache.
        /// </param>
        /// <param name="smallImageBufferedDiskCache">
        /// The buffered disk cache used for small images.
        /// </param>
        /// <param name="cacheKeyFactory">
        /// The factory that creates cache keys for the pipeline.
        /// </param>
        /// <param name="platformBitmapFactory">
        /// The bitmap factory used for post process.
        /// </param>
        /// <param name="flexByteArrayPool">
        /// The memory pool used for post process.
        /// </param>
        /// <param name="forceSmallCacheThresholdBytes">
        /// The threshold set for using the small buffered disk cache.
        /// </param>
        public ProducerFactory(
            IByteArrayPool byteArrayPool,
            ImageDecoder imageDecoder,
            IProgressiveJpegConfig progressiveJpegConfig,
            bool downsampleEnabled,
            bool resizeAndRotateEnabledForNetwork,
            IExecutorSupplier executorSupplier,
            IPooledByteBufferFactory pooledByteBufferFactory,
            IMemoryCache <ICacheKey, CloseableImage> bitmapMemoryCache,
            IMemoryCache <ICacheKey, IPooledByteBuffer> encodedMemoryCache,
            BufferedDiskCache defaultBufferedDiskCache,
            BufferedDiskCache smallImageBufferedDiskCache,
            ICacheKeyFactory cacheKeyFactory,
            PlatformBitmapFactory platformBitmapFactory,
            FlexByteArrayPool flexByteArrayPool,
            int forceSmallCacheThresholdBytes)
        {
            _forceSmallCacheThresholdBytes = forceSmallCacheThresholdBytes;

            _byteArrayPool                    = byteArrayPool;
            _imageDecoder                     = imageDecoder;
            _progressiveJpegConfig            = progressiveJpegConfig;
            _downsampleEnabled                = downsampleEnabled;
            _resizeAndRotateEnabledForNetwork = resizeAndRotateEnabledForNetwork;

            _executorSupplier        = executorSupplier;
            _pooledByteBufferFactory = pooledByteBufferFactory;

            _bitmapMemoryCache           = bitmapMemoryCache;
            _encodedMemoryCache          = encodedMemoryCache;
            _defaultBufferedDiskCache    = defaultBufferedDiskCache;
            _smallImageBufferedDiskCache = smallImageBufferedDiskCache;
            _cacheKeyFactory             = cacheKeyFactory;

            _platformBitmapFactory = platformBitmapFactory;
            _flexByteArrayPool     = flexByteArrayPool;
        }
        /// <summary>
        /// Start producing results for given context.
        /// Provided consumer is notified whenever progress is made
        /// (new value is ready or error occurs).
        /// </summary>
        public void ProduceResults(
            IConsumer <EncodedImage> consumer,
            IProducerContext producerContext)
        {
            ImageRequest imageRequest = producerContext.ImageRequest;

            if (!imageRequest.IsDiskCacheEnabled)
            {
                MaybeStartInputProducer(consumer, consumer, producerContext);
                return;
            }

            producerContext.Listener.OnProducerStart(producerContext.Id, PRODUCER_NAME);
            ICacheKey cacheKey = _cacheKeyFactory.GetEncodedCacheKey(
                imageRequest, producerContext.CallerContext);

            bool isSmallRequest = (imageRequest.CacheChoice == CacheChoice.SMALL);
            BufferedDiskCache preferredCache = isSmallRequest ?
                                               _smallImageBufferedDiskCache :
                                               _defaultBufferedDiskCache;

            AtomicBoolean       isCancelled = new AtomicBoolean(false);
            Task <EncodedImage> diskLookupTask;

            if (_chooseCacheByImageSize)
            {
                bool alreadyInSmall = _smallImageBufferedDiskCache.ContainsSync(cacheKey);
                bool alreadyInMain  = _defaultBufferedDiskCache.ContainsSync(cacheKey);
                BufferedDiskCache firstCache;
                BufferedDiskCache secondCache;
                if (alreadyInSmall || !alreadyInMain)
                {
                    firstCache  = _smallImageBufferedDiskCache;
                    secondCache = _defaultBufferedDiskCache;
                }
                else
                {
                    firstCache  = _defaultBufferedDiskCache;
                    secondCache = _smallImageBufferedDiskCache;
                }

                diskLookupTask = firstCache.Get(cacheKey, isCancelled);
                diskLookupTask = diskLookupTask.ContinueWith(
                    task =>
                {
                    if (IsTaskCancelled(task) || (!task.IsFaulted && task.Result != null))
                    {
                        return(task);
                    }

                    return(secondCache.Get(cacheKey, isCancelled));
                },
                    TaskContinuationOptions.ExecuteSynchronously)
                                 .Unwrap();
            }
            else
            {
                diskLookupTask = preferredCache.Get(cacheKey, isCancelled);
            }

            diskLookupTask.ContinueWith(
                task =>
            {
                OnFinishDiskReads(
                    task,
                    consumer,
                    preferredCache,
                    cacheKey,
                    producerContext);
            },
                TaskContinuationOptions.ExecuteSynchronously);

            SubscribeTaskForRequestCancellation(isCancelled, producerContext);
        }
        private void OnFinishDiskReads(
            Task <EncodedImage> task,
            IConsumer <EncodedImage> consumer,
            BufferedDiskCache preferredCache,
            ICacheKey preferredCacheKey,
            IProducerContext producerContext)
        {
            string            requestId = producerContext.Id;
            IProducerListener listener  = producerContext.Listener;

            if (IsTaskCancelled(task))
            {
                listener.OnProducerFinishWithCancellation(requestId, PRODUCER_NAME, null);
                consumer.OnCancellation();
            }
            else if (task.IsFaulted)
            {
                listener.OnProducerFinishWithFailure(requestId, PRODUCER_NAME, task.Exception, null);
                MaybeStartInputProducer(
                    consumer,
                    new DiskCacheConsumer(
                        _defaultBufferedDiskCache,
                        _smallImageBufferedDiskCache,
                        _chooseCacheByImageSize,
                        _forceSmallCacheThresholdBytes,
                        consumer,
                        preferredCache,
                        preferredCacheKey),
                    producerContext);
            }
            else
            {
                EncodedImage cachedReference = task.Result;
                if (cachedReference != null)
                {
                    listener.OnProducerFinishWithSuccess(
                        requestId,
                        PRODUCER_NAME,
                        GetExtraMap(listener, requestId, true));

                    consumer.OnProgressUpdate(1);
                    consumer.OnNewResult(cachedReference, true);
                    cachedReference.Dispose();
                }
                else
                {
                    listener.OnProducerFinishWithSuccess(
                        requestId,
                        PRODUCER_NAME,
                        GetExtraMap(listener, requestId, false));

                    MaybeStartInputProducer(
                        consumer,
                        new DiskCacheConsumer(
                            _defaultBufferedDiskCache,
                            _smallImageBufferedDiskCache,
                            _chooseCacheByImageSize,
                            _forceSmallCacheThresholdBytes,
                            consumer,
                            preferredCache,
                            preferredCacheKey),
                        producerContext);
                }
            }
        }