Skip to content
Snippets Groups Projects
Unverified Commit 2c75fac1 authored by Sergei Zharinov's avatar Sergei Zharinov Committed by GitHub
Browse files

fix(rubygems): Copy strings via buffers instead of slice hack (#21876)

parent 3b82013a
No related merge requests found
......@@ -45,12 +45,22 @@ const Lines = z
}
}
return { packageName, deletedVersions, addedVersions };
})
}),
{
onError: ({ error: err, input }) => {
logger.debug(
{ err, input },
'Rubygems: failed to parse some version lines'
);
},
}
)
);
type Lines = z.infer<typeof Lines>;
export class VersionsDatasource extends Datasource {
private isInitialFetch = true;
constructor(override readonly id: string) {
super(id);
}
......@@ -96,10 +106,22 @@ export class VersionsDatasource extends Datasource {
}
/**
* https://bugs.chromium.org/p/v8/issues/detail?id=2869
* Since each `/versions` reponse exceed 10MB,
* there is potential for a memory leak if we construct slices
* of the response body and cache them long-term:
*
* https://bugs.chromium.org/p/v8/issues/detail?id=2869
*
* This method meant to be called for `version` and `packageName`
* before storing them in the cache.
*/
private static copystr(x: string): string {
return (' ' + x).slice(1);
private copystr(x: string): string {
const len = Buffer.byteLength(x, 'utf8');
const buf = this.isInitialFetch
? Buffer.allocUnsafe(len) // allocate from pre-allocated buffer
: Buffer.allocUnsafeSlow(len); // allocate standalone buffer
buf.write(x, 'utf8');
return buf.toString('utf8');
}
private updatePackageReleases(
......@@ -107,7 +129,7 @@ export class VersionsDatasource extends Datasource {
lines: Lines
): void {
for (const line of lines) {
const packageName = VersionsDatasource.copystr(line.packageName);
const packageName = this.copystr(line.packageName);
let versions = packageReleases.get(packageName) ?? [];
const { deletedVersions, addedVersions } = line;
......@@ -120,7 +142,7 @@ export class VersionsDatasource extends Datasource {
const existingVersions = new Set(versions);
for (const addedVersion of addedVersions) {
if (!existingVersions.has(addedVersion)) {
const version = VersionsDatasource.copystr(addedVersion);
const version = this.copystr(addedVersion);
versions.push(version);
}
}
......@@ -169,6 +191,7 @@ export class VersionsDatasource extends Datasource {
const lines = Lines.parse(newLines);
this.updatePackageReleases(regCache.packageReleases, lines);
this.isInitialFetch = false;
}
private updateRubyGemsVersionsPromise: Promise<void> | null = null;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment