Merge pull request #12903 from Snuffleupagus/GlobalImageCache-byteSize

Improve global image caching for small images (PR 11912 follow-up, issue 12098)
This commit is contained in:
Tim van der Meij 2021-01-27 22:20:58 +01:00 committed by GitHub
commit d52e5b0505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 11 deletions

View File

@ -609,6 +609,9 @@ class PartialEvaluator {
.then(imageObj => { .then(imageObj => {
imgData = imageObj.createImageData(/* forceRGBA = */ false); imgData = imageObj.createImageData(/* forceRGBA = */ false);
if (cacheKey && imageRef && cacheGlobally) {
this.globalImageCache.addByteSize(imageRef, imgData.data.length);
}
return this._sendImgData(objId, imgData, cacheGlobally); return this._sendImgData(objId, imgData, cacheGlobally);
}) })
.catch(reason => { .catch(reason => {
@ -633,6 +636,7 @@ class PartialEvaluator {
objId, objId,
fn: OPS.paintImageXObject, fn: OPS.paintImageXObject,
args, args,
byteSize: 0, // Temporary entry, note `addByteSize` above.
}); });
} }
} }

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { assert, info, shadow, unreachable } from "../shared/util.js"; import { assert, shadow, unreachable, warn } from "../shared/util.js";
import { RefSetCache } from "./primitives.js"; import { RefSetCache } from "./primitives.js";
class BaseLocalCache { class BaseLocalCache {
@ -161,8 +161,12 @@ class GlobalImageCache {
return shadow(this, "NUM_PAGES_THRESHOLD", 2); return shadow(this, "NUM_PAGES_THRESHOLD", 2);
} }
static get MAX_IMAGES_TO_CACHE() { static get MIN_IMAGES_TO_CACHE() {
return shadow(this, "MAX_IMAGES_TO_CACHE", 10); return shadow(this, "MIN_IMAGES_TO_CACHE", 10);
}
static get MAX_BYTE_SIZE() {
return shadow(this, "MAX_BYTE_SIZE", /* Forty megabytes = */ 40e6);
} }
constructor() { constructor() {
@ -179,6 +183,24 @@ class GlobalImageCache {
this._imageCache = new RefSetCache(); this._imageCache = new RefSetCache();
} }
get _byteSize() {
let byteSize = 0;
this._imageCache.forEach(imageData => {
byteSize += imageData.byteSize;
});
return byteSize;
}
get _cacheLimitReached() {
if (this._imageCache.size < GlobalImageCache.MIN_IMAGES_TO_CACHE) {
return false;
}
if (this._byteSize < GlobalImageCache.MAX_BYTE_SIZE) {
return false;
}
return true;
}
shouldCache(ref, pageIndex) { shouldCache(ref, pageIndex) {
const pageIndexSet = this._refCache.get(ref); const pageIndexSet = this._refCache.get(ref);
const numPages = pageIndexSet const numPages = pageIndexSet
@ -188,10 +210,7 @@ class GlobalImageCache {
if (numPages < GlobalImageCache.NUM_PAGES_THRESHOLD) { if (numPages < GlobalImageCache.NUM_PAGES_THRESHOLD) {
return false; return false;
} }
if ( if (!this._imageCache.has(ref) && this._cacheLimitReached) {
!this._imageCache.has(ref) &&
this._imageCache.size >= GlobalImageCache.MAX_IMAGES_TO_CACHE
) {
return false; return false;
} }
return true; return true;
@ -206,6 +225,20 @@ class GlobalImageCache {
pageIndexSet.add(pageIndex); pageIndexSet.add(pageIndex);
} }
/**
* PLEASE NOTE: Must be called *after* the `setData` method.
*/
addByteSize(ref, byteSize) {
const imageData = this._imageCache.get(ref);
if (!imageData) {
return; // The image data isn't cached (the limit was reached).
}
if (imageData.byteSize) {
return; // The byte-size has already been set.
}
imageData.byteSize = byteSize;
}
getData(ref, pageIndex) { getData(ref, pageIndex) {
const pageIndexSet = this._refCache.get(ref); const pageIndexSet = this._refCache.get(ref);
if (!pageIndexSet) { if (!pageIndexSet) {
@ -232,10 +265,8 @@ class GlobalImageCache {
if (this._imageCache.has(ref)) { if (this._imageCache.has(ref)) {
return; return;
} }
if (this._imageCache.size >= GlobalImageCache.MAX_IMAGES_TO_CACHE) { if (this._cacheLimitReached) {
info( warn("GlobalImageCache.setData - cache limit reached.");
"GlobalImageCache.setData - ignoring image above MAX_IMAGES_TO_CACHE."
);
return; return;
} }
this._imageCache.put(ref, data); this._imageCache.put(ref, data);