From 63f6f2cefe1027cc9b35ca9e09dabd1d6ecd1c1c Mon Sep 17 00:00:00 2001 From: Eric Eldredge Date: Tue, 16 Nov 2021 19:03:06 -0500 Subject: [PATCH] Only stream large assets from cache Before, all assets were streamed from cache regardless of size, but by marking assets with content streams as large blobs when being written to the cache, we can default to reading the assets into memory from cache, and only stream the assets that were marked as large blobs. --- packages/core/core/src/PackagerRunner.js | 4 ++++ packages/core/core/src/Transformation.js | 4 +++- packages/core/core/src/UncommittedAsset.js | 1 + packages/core/core/src/requests/WriteBundleRequest.js | 11 +++++++++-- packages/core/core/src/types.js | 1 + 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/core/core/src/PackagerRunner.js b/packages/core/core/src/PackagerRunner.js index c062edc9da4..a71a7ef1e75 100644 --- a/packages/core/core/src/PackagerRunner.js +++ b/packages/core/core/src/PackagerRunner.js @@ -83,6 +83,7 @@ export type BundleInfo = {| +hashReferences: Array, +time?: number, +cacheKeys: CacheKeyMap, + +isLargeBlob: boolean, |}; type CacheKeyMap = {| @@ -618,9 +619,11 @@ export default class PackagerRunner { let size = 0; let hash; let hashReferences = []; + let isLargeBlob = false; // TODO: don't replace hash references in binary files?? if (contents instanceof Readable) { + isLargeBlob = true; let boundaryStr = ''; let h = new Hash(); await this.options.cache.setStream( @@ -659,6 +662,7 @@ export default class PackagerRunner { hash, hashReferences, cacheKeys, + isLargeBlob, }; await this.options.cache.set(cacheKeys.info, info); return info; diff --git a/packages/core/core/src/Transformation.js b/packages/core/core/src/Transformation.js index bdd18698f51..f2c0fab4f01 100644 --- a/packages/core/core/src/Transformation.js +++ b/packages/core/core/src/Transformation.js @@ -512,7 +512,9 @@ export default class Transformation { cachedAssets.map(async (value: AssetValue) => { let content = value.contentKey != null - ? this.options.cache.getStream(value.contentKey) + ? value.isLargeBlob + ? this.options.cache.getStream(value.contentKey) + : await this.options.cache.getBlob(value.contentKey) : null; let mapBuffer = value.astKey != null diff --git a/packages/core/core/src/UncommittedAsset.js b/packages/core/core/src/UncommittedAsset.js index ec199e6ca68..cd0fc9be2b6 100644 --- a/packages/core/core/src/UncommittedAsset.js +++ b/packages/core/core/src/UncommittedAsset.js @@ -135,6 +135,7 @@ export default class UncommittedAsset { this.value.stats.size = size; } + this.value.isLargeBlob = this.content instanceof Readable; this.value.committed = true; } diff --git a/packages/core/core/src/requests/WriteBundleRequest.js b/packages/core/core/src/requests/WriteBundleRequest.js index 80a997b41b7..c09fed60e93 100644 --- a/packages/core/core/src/requests/WriteBundleRequest.js +++ b/packages/core/core/src/requests/WriteBundleRequest.js @@ -16,7 +16,7 @@ import {HASH_REF_PREFIX, HASH_REF_REGEX} from '../constants'; import nullthrows from 'nullthrows'; import path from 'path'; import {NamedBundle} from '../public/Bundle'; -import {TapStream} from '@parcel/utils'; +import {blobToStream, TapStream} from '@parcel/utils'; import {Readable, Transform, pipeline} from 'stream'; import { fromProjectPath, @@ -123,7 +123,14 @@ async function run({input, options, api}: RunInput) { : { mode: (await inputFS.stat(mainEntry.filePath)).mode, }; - let contentStream = options.cache.getStream(cacheKeys.content); + let contentStream: Readable; + if (info.isLargeBlob) { + contentStream = options.cache.getStream(cacheKeys.content); + } else { + contentStream = blobToStream( + await options.cache.getBlob(cacheKeys.content), + ); + } let size = 0; contentStream = contentStream.pipe( new TapStream(buf => { diff --git a/packages/core/core/src/types.js b/packages/core/core/src/types.js index 6c498c47385..a93ffd73293 100644 --- a/packages/core/core/src/types.js +++ b/packages/core/core/src/types.js @@ -180,6 +180,7 @@ export type Asset = {| configPath?: ProjectPath, plugin: ?PackageName, configKeyPath?: string, + isLargeBlob?: boolean, |}; export type InternalGlob = ProjectPath;