1+ /*
2+ Copyright (c) 2024-2025, Oracle and/or its affiliates.
3+
4+ Licensed under the Apache License, Version 2.0 (the "License");
5+ you may not use this file except in compliance with the License.
6+ You may obtain a copy of the License at
7+
8+ https://www.apache.org/licenses/LICENSE-2.0
9+
10+ Unless required by applicable law or agreed to in writing, software
11+ distributed under the License is distributed on an "AS IS" BASIS,
12+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ See the License for the specific language governing permissions and
14+ limitations under the License.
15+ */
16+ import { CacheService } from "../../types" ;
17+ import { LOGGER } from "../../../logger" ;
18+ import { globalState } from "../../../globalState" ;
19+ import { isError } from "../../../utils" ;
20+ import { removeEntriesOnOverflow } from "./utils" ;
21+ import { ProjectCacheValue } from "./projectCacheValue" ;
22+
23+ export class ProjectCacheService implements CacheService < ProjectCacheValue , String > {
24+ readonly MAX_KEYS_SIZE : number = 5000 ;
25+ private removingKeys : boolean = false ;
26+
27+ public get = ( key : string ) => {
28+ try {
29+ const updatedKey = this . getUpdatedKey ( key ) ;
30+ const vscGlobalState = globalState . getExtensionContextInfo ( ) . getVscGlobalState ( ) ;
31+
32+ const value = vscGlobalState . get < ProjectCacheValue > ( updatedKey ) ;
33+ if ( value ) {
34+ this . put ( updatedKey , ProjectCacheValue . fromObject ( { ...value , lastUsed : Date . now ( ) } ) ) ;
35+ }
36+
37+ return value ?. payload ;
38+ } catch ( err ) {
39+ LOGGER . error ( `Error while retrieving ${ key } from cache: ${ ( err as Error ) . message } ` ) ;
40+ return undefined ;
41+ }
42+ }
43+
44+ public put = async ( key : string , value : ProjectCacheValue ) => {
45+ try {
46+ const updatedKey = this . getUpdatedKey ( key ) ;
47+ const vscGlobalState = globalState . getExtensionContextInfo ( ) . getVscGlobalState ( ) ;
48+
49+ await vscGlobalState . update ( updatedKey , value ) ;
50+ if ( vscGlobalState . keys ( ) . length > this . MAX_KEYS_SIZE ) {
51+ this . removeOnOverflow ( ) ;
52+ }
53+ LOGGER . debug ( `Updating key: ${ key } to ${ value } ` ) ;
54+
55+ return true ;
56+ } catch ( err ) {
57+ LOGGER . error ( `Error while storing ${ key } in cache: ${ ( err as Error ) . message } ` ) ;
58+ return false ;
59+ }
60+ }
61+
62+ public removeOnOverflow = async ( ) => {
63+ try {
64+ if ( this . removingKeys ) {
65+ LOGGER . log ( "Ignoring removing keys request, since it is already in progress" ) ;
66+ return ;
67+ }
68+ this . removingKeys = true ;
69+
70+ const vscGlobalState = globalState . getExtensionContextInfo ( ) . getVscGlobalState ( ) ;
71+ const comparator = ( a : ProjectCacheValue , b : ProjectCacheValue ) => ( a . lastUsed - b . lastUsed ) ;
72+
73+ await removeEntriesOnOverflow ( vscGlobalState , ProjectCacheValue . type , comparator ) ;
74+ } catch ( error ) {
75+ LOGGER . error ( "Some error occurred while removing keys " + ( isError ( error ) ? error . message : error ) ) ;
76+ } finally {
77+ this . removingKeys = false ;
78+ }
79+ }
80+
81+ // for unit tests needs to be public
82+ public getUpdatedKey = ( key : string ) => `${ ProjectCacheValue . type } .${ key } ` ;
83+ }
0 commit comments