From 86735d75b5a192abe984e68c12f876496a3a82c0 Mon Sep 17 00:00:00 2001
From: Sergei Zharinov <zharinov@users.noreply.github.com>
Date: Sat, 20 May 2023 15:11:45 +0300
Subject: [PATCH] refactor(rubygems): Extract `copystring` function to the
 utils (#22322)

---
 .../rubygems/versions-datasource.ts           | 27 +++----------------
 lib/util/string.ts                            | 15 +++++++++++
 2 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/lib/modules/datasource/rubygems/versions-datasource.ts b/lib/modules/datasource/rubygems/versions-datasource.ts
index 1e56a5d899..a6d5de0bda 100644
--- a/lib/modules/datasource/rubygems/versions-datasource.ts
+++ b/lib/modules/datasource/rubygems/versions-datasource.ts
@@ -6,6 +6,7 @@ import { getElapsedMinutes } from '../../../util/date';
 import { HttpError } from '../../../util/http';
 import { newlineRegex } from '../../../util/regex';
 import { LooseArray } from '../../../util/schema-utils';
+import { copystr } from '../../../util/string';
 import { Datasource } from '../datasource';
 import type { GetReleasesConfig, ReleaseResult } from '../types';
 
@@ -51,8 +52,6 @@ const Lines = z
 type Lines = z.infer<typeof Lines>;
 
 export class VersionsDatasource extends Datasource {
-  private isInitialFetch = true;
-
   constructor(override readonly id: string) {
     super(id);
   }
@@ -97,31 +96,12 @@ export class VersionsDatasource extends Datasource {
     return { releases };
   }
 
-  /**
-   * 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 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(
     packageReleases: PackageReleases,
     lines: Lines
   ): void {
     for (const line of lines) {
-      const packageName = this.copystr(line.packageName);
+      const packageName = copystr(line.packageName);
       let versions = packageReleases.get(packageName) ?? [];
 
       const { deletedVersions, addedVersions } = line;
@@ -134,7 +114,7 @@ export class VersionsDatasource extends Datasource {
         const existingVersions = new Set(versions);
         for (const addedVersion of addedVersions) {
           if (!existingVersions.has(addedVersion)) {
-            const version = this.copystr(addedVersion);
+            const version = copystr(addedVersion);
             versions.push(version);
           }
         }
@@ -183,7 +163,6 @@ export class VersionsDatasource extends Datasource {
 
     const lines = Lines.parse(newLines);
     this.updatePackageReleases(regCache.packageReleases, lines);
-    this.isInitialFetch = false;
   }
 
   private updateRubyGemsVersionsPromise: Promise<void> | null = null;
diff --git a/lib/util/string.ts b/lib/util/string.ts
index 7a4d7d8760..d62a1be1a2 100644
--- a/lib/util/string.ts
+++ b/lib/util/string.ts
@@ -67,3 +67,18 @@ export function titleCase(input: string): string {
 
   return words.join(' ');
 }
+
+/**
+ * Sometimes we extract small strings from a multi-megabyte files.
+ * If we then save them in the in-memory cache, V8 may not free
+ * the initial buffer, which can lead to memory leaks:
+ *
+ *   https://bugs.chromium.org/p/v8/issues/detail?id=2869
+ *
+ */
+export function copystr(x: string): string {
+  const len = Buffer.byteLength(x, 'utf8');
+  const buf = Buffer.allocUnsafeSlow(len);
+  buf.write(x, 'utf8');
+  return buf.toString('utf8');
+}
-- 
GitLab