@@ -2,7 +2,7 @@ import fs, { promises as fsPromises } from 'fs'
22import path from 'path'
33
44import QuickLRU from 'quick-lru'
5- import { brotliDecompress } from 'zlib'
5+ import { brotliDecompress , deflateSync , inflateSync } from 'zlib'
66import { promisify } from 'util'
77import { getAutomatedPageMiniTocItems , type MiniTocItem } from '@/frame/lib/get-mini-toc-items'
88import { allVersions , getOpenApiVersion } from '@/versions/lib/all-versions'
@@ -60,7 +60,7 @@ const restOperationData = new Map<
6060// they account for >90% of traffic and each version needs ~100 slots alone.
6161// All other versions (ghes) go into a bounded LRU cache.
6262const PINNED_OPEN_API_VERSIONS = new Set ( [ 'fpt' , 'ghec' ] )
63- export const pinnedCache = new Map < string , RestOperationCategory > ( ) // @internal
63+ export const pinnedCache = new Map < string , Buffer > ( ) // @internal — stores deflate-compressed JSON
6464const LRU_MAX_SIZE = Math . max ( 1 , parseInt ( process . env . REST_SCHEMA_LRU_SIZE ?? '' , 10 ) || 96 )
6565export const lruCache = new QuickLRU < string , RestOperationCategory > ( { maxSize : LRU_MAX_SIZE } ) // @internal
6666
@@ -106,20 +106,39 @@ export default async function getRest(
106106 const openapiSchemaName = apiVersion ? `${ openApiVersion } -${ apiVersion } ` : `${ openApiVersion } `
107107 const lruKey = `${ openApiVersion } :${ apiDate } :${ category } `
108108
109- const cache = PINNED_OPEN_API_VERSIONS . has ( openApiVersion ) ? pinnedCache : lruCache
109+ const isPinned = PINNED_OPEN_API_VERSIONS . has ( openApiVersion )
110110
111- if ( ! cache . has ( lruKey ) ) {
111+ // Pinned cache: store deflate-compressed JSON Buffers to save ~100–500 MB heap.
112+ // LRU cache: store parsed objects (bounded size, low traffic).
113+ if ( isPinned ) {
114+ if ( pinnedCache . has ( lruKey ) ) {
115+ return JSON . parse ( inflateSync ( pinnedCache . get ( lruKey ) ! ) . toString ( ) ) as RestOperationCategory
116+ }
117+ const basePath = path . join ( REST_DATA_DIR , openapiSchemaName , `${ category } .json` )
118+ if ( ! inflight . has ( lruKey ) ) {
119+ inflight . set (
120+ lruKey ,
121+ loadCategoryFile ( basePath ) . finally ( ( ) => inflight . delete ( lruKey ) ) ,
122+ )
123+ }
124+ const data = await inflight . get ( lruKey ) !
125+ pinnedCache . set ( lruKey , deflateSync ( Buffer . from ( JSON . stringify ( data ) ) ) )
126+ return data
127+ } else {
128+ if ( lruCache . has ( lruKey ) ) {
129+ return lruCache . get ( lruKey ) !
130+ }
112131 const basePath = path . join ( REST_DATA_DIR , openapiSchemaName , `${ category } .json` )
113132 if ( ! inflight . has ( lruKey ) ) {
114133 inflight . set (
115134 lruKey ,
116135 loadCategoryFile ( basePath ) . finally ( ( ) => inflight . delete ( lruKey ) ) ,
117136 )
118137 }
119- cache . set ( lruKey , await inflight . get ( lruKey ) ! )
138+ const data = await inflight . get ( lruKey ) !
139+ lruCache . set ( lruKey , data )
140+ return data
120141 }
121-
122- return cache . get ( lruKey ) !
123142}
124143
125144// Read asynchronously to avoid blocking the event loop on a cache miss.
0 commit comments