From d8d3d92cacde674dd19fbf54856c93e3d05783c4 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 21 Sep 2022 15:59:37 +0530 Subject: [PATCH 1/9] add lifoProcessing options --- src/services/queueProcessor.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/services/queueProcessor.ts b/src/services/queueProcessor.ts index 5f5e939c6..93d81a15a 100644 --- a/src/services/queueProcessor.ts +++ b/src/services/queueProcessor.ts @@ -17,7 +17,10 @@ export default class QueueProcessor { private requestInProcessing = 0; - constructor(private maxParallelProcesses: number) {} + constructor( + private maxParallelProcesses: number, + private lifoProcessing = false + ) {} public queueUpRequest( request: (canceller?: RequestCanceller) => Promise @@ -52,7 +55,9 @@ export default class QueueProcessor { private async processQueue() { while (this.requestQueue.length > 0) { - const queueItem = this.requestQueue.shift(); + const queueItem = this.lifoProcessing + ? this.requestQueue.pop() + : this.requestQueue.shift(); let response = null; if (queueItem.isCanceled.status) { From e68de4b35c44d437f0aa8aedb9ccf2f4b326898e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 21 Sep 2022 16:00:32 +0530 Subject: [PATCH 2/9] add download lifo processor --- src/services/downloadManager.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index ca45c22ae..621f85eba 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -13,11 +13,17 @@ import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; import { CustomError } from 'utils/error'; import { openThumbnailCache } from './cacheService'; +import QueueProcessor from './queueProcessor'; class DownloadManager { private fileObjectURLPromise = new Map>(); private thumbnailObjectURLPromise = new Map>(); + private thumbnailDownloadRequestsProcessor = new QueueProcessor( + 5, + true + ); + public async getThumbnail(file: EnteFile) { try { const token = getToken(); @@ -34,7 +40,10 @@ class DownloadManager { if (cacheResp) { return URL.createObjectURL(await cacheResp.blob()); } - const thumb = await this.downloadThumb(token, file); + const thumb = + await this.thumbnailDownloadRequestsProcessor.queueUpRequest( + () => this.downloadThumb(token, file) + ).promise; const thumbBlob = new Blob([thumb]); thumbnailCache From c24732e78989656b1f126037352b39d2282369a5 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 21 Sep 2022 16:01:22 +0530 Subject: [PATCH 3/9] remove over scanning as they are getting processed before --- src/components/PhotoList.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index b2157f12c..42eac665b 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -24,7 +24,7 @@ import { GalleryContext } from 'pages/gallery'; import { SpecialPadding } from 'styles/SpecialPadding'; const A_DAY = 24 * 60 * 60 * 1000; -const NO_OF_PAGES = 2; +// const NO_OF_PAGES = 2; const FOOTER_HEIGHT = 90; export enum ITEM_TYPE { @@ -512,9 +512,9 @@ export function PhotoList({ } }; - const extraRowsToRender = Math.ceil( - (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT - ); + // const extraRowsToRender = Math.ceil( + // (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT + // ); const generateKey = (index) => { switch (timeStampList[index].itemType) { @@ -587,7 +587,7 @@ export function PhotoList({ width={width} itemCount={timeStampList.length} itemKey={generateKey} - overscanCount={extraRowsToRender}> + overscanCount={0}> {({ index, style }) => ( Date: Wed, 21 Sep 2022 17:55:25 +0530 Subject: [PATCH 4/9] add logic to show placeholder when user is scrolling --- src/components/PhotoFrame.tsx | 7 ++- src/components/PhotoList.tsx | 29 ++++++---- src/components/pages/gallery/PreviewCard.tsx | 61 ++++++++------------ 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 780563cd0..3973713f1 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -426,7 +426,11 @@ const PhotoFrame = ({ handleSelect(filteredData[index].id, index)(!checked); } }; - const getThumbnail = (files: EnteFile[], index: number) => + const getThumbnail = ( + files: EnteFile[], + index: number, + isScrolling: boolean + ) => files[index] ? ( = currentHover && index <= rangeStart) } activeCollection={activeCollection} + showPlaceholder={isScrolling} /> ) : ( <> diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index 42eac665b..3fb837352 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -24,7 +24,7 @@ import { GalleryContext } from 'pages/gallery'; import { SpecialPadding } from 'styles/SpecialPadding'; const A_DAY = 24 * 60 * 60 * 1000; -// const NO_OF_PAGES = 2; +const NO_OF_PAGES = 1; const FOOTER_HEIGHT = 90; export enum ITEM_TYPE { @@ -153,7 +153,11 @@ interface Props { width: number; filteredData: EnteFile[]; showAppDownloadBanner: boolean; - getThumbnail: (files: EnteFile[], index: number) => JSX.Element; + getThumbnail: ( + files: EnteFile[], + index: number, + isScrolling?: boolean + ) => JSX.Element; activeCollection: number; resetFetching: () => void; } @@ -512,9 +516,9 @@ export function PhotoList({ } }; - // const extraRowsToRender = Math.ceil( - // (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT - // ); + const extraRowsToRender = Math.ceil( + (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT + ); const generateKey = (index) => { switch (timeStampList[index].itemType) { @@ -527,7 +531,10 @@ export function PhotoList({ } }; - const renderListItem = (listItem: TimeStampListItem) => { + const renderListItem = ( + listItem: TimeStampListItem, + isScrolling: boolean + ) => { switch (listItem.itemType) { case ITEM_TYPE.TIME: return listItem.dates ? ( @@ -556,7 +563,8 @@ export function PhotoList({ const ret = listItem.items.map((item, idx) => getThumbnail( filteredDataCopy, - listItem.itemStartIndex + idx + listItem.itemStartIndex + idx, + isScrolling ) ); if (listItem.groups) { @@ -587,14 +595,15 @@ export function PhotoList({ width={width} itemCount={timeStampList.length} itemKey={generateKey} - overscanCount={0}> - {({ index, style }) => ( + overscanCount={extraRowsToRender} + useIsScrolling> + {({ index, style, isScrolling }) => ( - {renderListItem(timeStampList[index])} + {renderListItem(timeStampList[index], isScrolling)} )} diff --git a/src/components/pages/gallery/PreviewCard.tsx b/src/components/pages/gallery/PreviewCard.tsx index 71344c7e2..0cebef805 100644 --- a/src/components/pages/gallery/PreviewCard.tsx +++ b/src/components/pages/gallery/PreviewCard.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useLayoutEffect, useRef, useState } from 'react'; +import React, { useContext, useLayoutEffect, useState } from 'react'; import { EnteFile } from 'types/file'; import { styled } from '@mui/material'; import PlayCircleOutlineOutlinedIcon from '@mui/icons-material/PlayCircleOutlineOutlined'; @@ -18,18 +18,18 @@ import { formatDateRelative } from 'utils/time'; interface IProps { file: EnteFile; - updateURL?: (url: string) => EnteFile; - onClick?: () => void; - forcedEnable?: boolean; - selectable?: boolean; - selected?: boolean; - onSelect?: (checked: boolean) => void; - onHover?: () => void; - onRangeSelect?: () => void; - isRangeSelectActive?: boolean; - selectOnClick?: boolean; - isInsSelectRange?: boolean; - activeCollection?: number; + updateURL: (url: string) => EnteFile; + onClick: () => void; + selectable: boolean; + selected: boolean; + onSelect: (checked: boolean) => void; + onHover: () => void; + onRangeSelect: () => void; + isRangeSelectActive: boolean; + selectOnClick: boolean; + isInsSelectRange: boolean; + activeCollection: number; + showPlaceholder: boolean; } const Check = styled('input')<{ active: boolean }>` @@ -203,7 +203,6 @@ export default function PreviewCard(props: IProps) { file, onClick, updateURL, - forcedEnable, selectable, selected, onSelect, @@ -213,14 +212,13 @@ export default function PreviewCard(props: IProps) { isRangeSelectActive, isInsSelectRange, } = props; - const isMounted = useRef(true); const publicCollectionGalleryContext = useContext( PublicCollectionGalleryContext ); const deduplicateContext = useContext(DeduplicateContext); useLayoutEffect(() => { - if (file && !file.msrc) { + if (file && !file.msrc && !props.showPlaceholder) { const main = async () => { try { let url; @@ -236,18 +234,14 @@ export default function PreviewCard(props: IProps) { } else { url = await DownloadManager.getThumbnail(file); } - if (isMounted.current) { - setImgSrc(url); - thumbs.set(file.id, url); - if (updateURL) { - const newFile = updateURL(url); - file.msrc = newFile.msrc; - file.html = newFile.html; - file.src = newFile.src; - file.w = newFile.w; - file.h = newFile.h; - } - } + setImgSrc(url); + thumbs.set(file.id, url); + const newFile = updateURL(url); + file.msrc = newFile.msrc; + file.html = newFile.html; + file.src = newFile.src; + file.w = newFile.w; + file.h = newFile.h; } catch (e) { logError(e, 'preview card useEffect failed'); // no-op @@ -262,12 +256,7 @@ export default function PreviewCard(props: IProps) { main(); } } - - return () => { - // cool cool cool - isMounted.current = false; - }; - }, [file]); + }, [file, props.showPlaceholder]); const handleClick = () => { if (selectOnClick) { @@ -300,10 +289,10 @@ export default function PreviewCard(props: IProps) { return ( {selectable && ( Date: Wed, 21 Sep 2022 17:55:39 +0530 Subject: [PATCH 5/9] remove lifo processing --- src/services/queueProcessor.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/services/queueProcessor.ts b/src/services/queueProcessor.ts index 93d81a15a..5f5e939c6 100644 --- a/src/services/queueProcessor.ts +++ b/src/services/queueProcessor.ts @@ -17,10 +17,7 @@ export default class QueueProcessor { private requestInProcessing = 0; - constructor( - private maxParallelProcesses: number, - private lifoProcessing = false - ) {} + constructor(private maxParallelProcesses: number) {} public queueUpRequest( request: (canceller?: RequestCanceller) => Promise @@ -55,9 +52,7 @@ export default class QueueProcessor { private async processQueue() { while (this.requestQueue.length > 0) { - const queueItem = this.lifoProcessing - ? this.requestQueue.pop() - : this.requestQueue.shift(); + const queueItem = this.requestQueue.shift(); let response = null; if (queueItem.isCanceled.status) { From 81026c44142ce6892710c8e8fc23cd3b38a0eefb Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 21 Sep 2022 17:55:52 +0530 Subject: [PATCH 6/9] update thumbnailDownloadRequestsProcessor --- src/services/downloadManager.ts | 5 +---- src/services/publicCollectionDownloadManager.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index 621f85eba..b0d238670 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -19,10 +19,7 @@ class DownloadManager { private fileObjectURLPromise = new Map>(); private thumbnailObjectURLPromise = new Map>(); - private thumbnailDownloadRequestsProcessor = new QueueProcessor( - 5, - true - ); + private thumbnailDownloadRequestsProcessor = new QueueProcessor(5); public async getThumbnail(file: EnteFile) { try { diff --git a/src/services/publicCollectionDownloadManager.ts b/src/services/publicCollectionDownloadManager.ts index d649fced6..ba16e37b0 100644 --- a/src/services/publicCollectionDownloadManager.ts +++ b/src/services/publicCollectionDownloadManager.ts @@ -14,11 +14,14 @@ import { EnteFile } from 'types/file'; import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; import { CustomError } from 'utils/error'; +import QueueProcessor from './queueProcessor'; class PublicCollectionDownloadManager { private fileObjectURLPromise = new Map>(); private thumbnailObjectURLPromise = new Map>(); + private thumbnailDownloadRequestsProcessor = new QueueProcessor(5); + public async getThumbnail( file: EnteFile, token: string, @@ -46,11 +49,10 @@ class PublicCollectionDownloadManager { if (cacheResp) { return URL.createObjectURL(await cacheResp.blob()); } - const thumb = await this.downloadThumb( - token, - passwordToken, - file - ); + const thumb = + await this.thumbnailDownloadRequestsProcessor.queueUpRequest( + () => this.downloadThumb(token, passwordToken, file) + ).promise; const thumbBlob = new Blob([thumb]); try { await thumbnailCache?.put( From d80aaf3fff69e8e9fe461af7baaaf67d72f06a53 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 22 Sep 2022 13:32:46 +0530 Subject: [PATCH 7/9] remove over-scanning --- src/components/PhotoList.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index 3fb837352..6618d579f 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -24,7 +24,6 @@ import { GalleryContext } from 'pages/gallery'; import { SpecialPadding } from 'styles/SpecialPadding'; const A_DAY = 24 * 60 * 60 * 1000; -const NO_OF_PAGES = 1; const FOOTER_HEIGHT = 90; export enum ITEM_TYPE { @@ -516,10 +515,6 @@ export function PhotoList({ } }; - const extraRowsToRender = Math.ceil( - (NO_OF_PAGES * height) / IMAGE_CONTAINER_MAX_HEIGHT - ); - const generateKey = (index) => { switch (timeStampList[index].itemType) { case ITEM_TYPE.FILE: @@ -595,7 +590,7 @@ export function PhotoList({ width={width} itemCount={timeStampList.length} itemKey={generateKey} - overscanCount={extraRowsToRender} + overscanCount={0} useIsScrolling> {({ index, style, isScrolling }) => ( From 5d3dfa22ca71c28d4c5e7998c36419d0a8b1713d Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 22 Sep 2022 13:35:04 +0530 Subject: [PATCH 8/9] add option to set processingStrategy --- src/services/downloadManager.ts | 7 +++++-- src/services/queueProcessor.ts | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index b0d238670..2c04a1384 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -13,13 +13,16 @@ import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; import { CustomError } from 'utils/error'; import { openThumbnailCache } from './cacheService'; -import QueueProcessor from './queueProcessor'; +import QueueProcessor, { PROCESSING_STRATEGY } from './queueProcessor'; class DownloadManager { private fileObjectURLPromise = new Map>(); private thumbnailObjectURLPromise = new Map>(); - private thumbnailDownloadRequestsProcessor = new QueueProcessor(5); + private thumbnailDownloadRequestsProcessor = new QueueProcessor( + 5, + PROCESSING_STRATEGY.LIFO + ); public async getThumbnail(file: EnteFile) { try { diff --git a/src/services/queueProcessor.ts b/src/services/queueProcessor.ts index 5f5e939c6..ad63d3227 100644 --- a/src/services/queueProcessor.ts +++ b/src/services/queueProcessor.ts @@ -8,6 +8,11 @@ interface RequestQueueItem { canceller: { exec: () => void }; } +export enum PROCESSING_STRATEGY { + FIFO, + LIFO, +} + export interface RequestCanceller { exec: () => void; } @@ -17,7 +22,10 @@ export default class QueueProcessor { private requestInProcessing = 0; - constructor(private maxParallelProcesses: number) {} + constructor( + private maxParallelProcesses: number, + private processingStrategy = PROCESSING_STRATEGY.FIFO + ) {} public queueUpRequest( request: (canceller?: RequestCanceller) => Promise @@ -52,7 +60,10 @@ export default class QueueProcessor { private async processQueue() { while (this.requestQueue.length > 0) { - const queueItem = this.requestQueue.shift(); + const queueItem = + this.processingStrategy === PROCESSING_STRATEGY.LIFO + ? this.requestQueue.pop() + : this.requestQueue.shift(); let response = null; if (queueItem.isCanceled.status) { From 006ad4092560eeaac7e7697d683f86325dec9683 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 22 Sep 2022 14:07:47 +0530 Subject: [PATCH 9/9] add MAX_PARALLEL_DOWNLOADS --- src/services/downloadManager.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/downloadManager.ts b/src/services/downloadManager.ts index 2c04a1384..02051a3a6 100644 --- a/src/services/downloadManager.ts +++ b/src/services/downloadManager.ts @@ -15,12 +15,14 @@ import { CustomError } from 'utils/error'; import { openThumbnailCache } from './cacheService'; import QueueProcessor, { PROCESSING_STRATEGY } from './queueProcessor'; +const MAX_PARALLEL_DOWNLOADS = 10; + class DownloadManager { private fileObjectURLPromise = new Map>(); private thumbnailObjectURLPromise = new Map>(); private thumbnailDownloadRequestsProcessor = new QueueProcessor( - 5, + MAX_PARALLEL_DOWNLOADS, PROCESSING_STRATEGY.LIFO );