Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add large blob storage to Cache #7198

Merged
merged 24 commits into from Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f99e407
Add large blob methods to cache
lettertwo Oct 26, 2021
f6c22d7
Cache request graph as large blob
lettertwo Oct 26, 2021
8f0a103
Fix LMDBCache serialization
lettertwo Oct 27, 2021
aec63a8
Prepare LMDBCache fs for serialization
lettertwo Oct 27, 2021
2189909
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Oct 29, 2021
6681eef
Cache graph request results as large blobs
lettertwo Nov 2, 2021
9fa5e09
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Nov 2, 2021
6c88b5d
Revert configurable LMDBCache FS
lettertwo Nov 2, 2021
74b4dd4
Fall back to FS for large blobs in LMDBCache
lettertwo Nov 3, 2021
28c5b66
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Nov 3, 2021
5734312
Remove stale value when auto storing a large blob
lettertwo Nov 3, 2021
da0a359
Stream large blobs out of fs cache
lettertwo Nov 3, 2021
847f8be
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Nov 15, 2021
e13e8d0
Merge branch 'v2' into lettertwo/cache-large-blob
devongovett Nov 16, 2021
a53b39b
Revert fall back to FS for large blobs in LMDBCache
lettertwo Nov 16, 2021
ce8fe8e
Prevent large blobs from being stored in cache
lettertwo Nov 16, 2021
6d9f276
Set/get streams to/from FS in LMDBCache
lettertwo Nov 16, 2021
63f6f2c
Only stream large assets from cache
lettertwo Nov 17, 2021
50dfd3b
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Nov 18, 2021
0776a9e
Remove default empty stream from `getStream`
lettertwo Nov 18, 2021
d9fc18f
Differentiate large blobs in FSCache
lettertwo Nov 18, 2021
ed1b602
Fix type error
lettertwo Nov 18, 2021
88b1e22
Merge branch 'v2' into lettertwo/cache-large-blob
lettertwo Nov 22, 2021
3f3c831
Remove vestigial isLargeBlob check
lettertwo Nov 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/core/cache/src/FSCache.js
Expand Up @@ -77,6 +77,18 @@ export class FSCache implements Cache {
}
}

hasLargeBlob(key: string): Promise<boolean> {
return this.has(key);
}

getLargeBlob(key: string): Promise<Buffer> {
return this.getBlob(key);
}

setLargeBlob(key: string, contents: Buffer | string): Promise<void> {
return this.setBlob(key, contents);
}

async get<T>(key: string): Promise<?T> {
try {
let data = await this.fs.readFile(this._getCachePath(key));
Expand Down
32 changes: 27 additions & 5 deletions packages/core/cache/src/LMDBCache.js
@@ -1,21 +1,30 @@
// @flow strict-local
import type {Readable} from 'stream';
import type {FilePath} from '@parcel/types';
import type {FileSystem} from '@parcel/fs';
import type {Cache} from './types';

import {serialize, deserialize, registerSerializableClass} from '@parcel/core';
import path from 'path';
import {
serialize,
deserialize,
prepareForSerialization,
registerSerializableClass,
} from '@parcel/core';
import {blobToStream, bufferStream} from '@parcel/utils';
// flowlint-next-line untyped-import:off
import packageJson from '../package.json';
// $FlowFixMe
import lmdb from 'lmdb-store';

export class LMDBCache implements Cache {
fs: FileSystem;
dir: FilePath;
// $FlowFixMe
store: any;

constructor(cacheDir: FilePath) {
constructor(fs: FileSystem, cacheDir: FilePath) {
this.fs = fs;
this.dir = cacheDir;

this.store = lmdb.open(cacheDir, {
Expand All @@ -29,14 +38,15 @@ export class LMDBCache implements Cache {
return Promise.resolve();
}

serialize(): {|dir: FilePath|} {
serialize(): {|fs: FileSystem, dir: FilePath|} {
return {
fs: prepareForSerialization(this.fs),
dir: this.dir,
};
lettertwo marked this conversation as resolved.
Show resolved Hide resolved
}

static deserialize(opts: {|dir: FilePath|}): LMDBCache {
return new LMDBCache(opts.dir);
static deserialize(opts: {|fs: FileSystem, dir: FilePath|}): LMDBCache {
return new LMDBCache(opts.fs, opts.dir);
}

has(key: string): Promise<boolean> {
Expand Down Expand Up @@ -79,6 +89,18 @@ export class LMDBCache implements Cache {
getBuffer(key: string): Promise<?Buffer> {
return Promise.resolve(this.store.get(key));
}

hasLargeBlob(key: string): Promise<boolean> {
return this.fs.exists(path.join(this.dir, key));
}

getLargeBlob(key: string): Promise<Buffer> {
return this.fs.readFile(path.join(this.dir, key));
}

async setLargeBlob(key: string, contents: Buffer | string): Promise<void> {
await this.fs.writeFile(path.join(this.dir, key), contents);
}
}

registerSerializableClass(`${packageJson.version}:LMDBCache`, LMDBCache);
3 changes: 3 additions & 0 deletions packages/core/cache/src/types.js
Expand Up @@ -10,5 +10,8 @@ export interface Cache {
setStream(key: string, stream: Readable): Promise<void>;
getBlob(key: string): Promise<Buffer>;
setBlob(key: string, contents: Buffer | string): Promise<void>;
hasLargeBlob(key: string): Promise<boolean>;
getLargeBlob(key: string): Promise<Buffer>;
setLargeBlob(key: string, contents: Buffer | string): Promise<void>;
getBuffer(key: string): Promise<?Buffer>;
}
12 changes: 8 additions & 4 deletions packages/core/core/src/RequestTracker.js
Expand Up @@ -24,6 +24,7 @@ import {
} from '@parcel/utils';
import {hashString} from '@parcel/hash';
import {ContentGraph} from '@parcel/graph';
import {deserialize, serialize} from './serializer';
import {assertSignalNotAborted, hashFromOption} from './utils';
import {
type ProjectPath,
Expand Down Expand Up @@ -1039,7 +1040,9 @@ export default class RequestTracker {
}
}

promises.push(this.options.cache.set(requestGraphKey, this.graph));
promises.push(
this.options.cache.setLargeBlob(requestGraphKey, serialize(this.graph)),
);

let opts = getWatcherOptions(this.options);
let snapshotPath = path.join(this.options.cacheDir, snapshotKey + '.txt');
Expand Down Expand Up @@ -1083,9 +1086,10 @@ async function loadRequestGraph(options): Async<RequestGraph> {

let cacheKey = getCacheKey(options);
let requestGraphKey = hashString(`${cacheKey}:requestGraph`);
let requestGraph = await options.cache.get<RequestGraph>(requestGraphKey);

if (requestGraph) {
if (await options.cache.hasLargeBlob(requestGraphKey)) {
let requestGraph: RequestGraph = deserialize(
await options.cache.getLargeBlob(requestGraphKey),
);
let opts = getWatcherOptions(options);
let snapshotKey = hashString(`${cacheKey}:snapshot`);
let snapshotPath = path.join(options.cacheDir, snapshotKey + '.txt');
Expand Down
2 changes: 1 addition & 1 deletion packages/core/core/src/resolveOptions.js
Expand Up @@ -74,7 +74,7 @@ export default async function resolveOptions(
let cache =
initialOptions.cache ??
(outputFS instanceof NodeFS
? new LMDBCache(cacheDir)
? new LMDBCache(outputFS, cacheDir)
: new FSCache(outputFS, cacheDir));

let mode = initialOptions.mode ?? 'development';
Expand Down