3030import java .util .SortedMap ;
3131import java .util .TreeMap ;
3232import java .util .concurrent .ConcurrentHashMap ;
33+ import java .util .concurrent .ConcurrentMap ;
3334import java .util .stream .Collectors ;
3435
36+ import org .apache .commons .codec .digest .DigestUtils ;
3537import org .apache .commons .lang3 .tuple .Pair ;
3638import org .eclipse .lsp4j .Location ;
3739import org .slf4j .Logger ;
6668public class IndexCacheOnDiscDeltaBased implements IndexCache {
6769
6870 private final File cacheDirectory ;
69- private final Map <IndexCacheKey , Map < String , Long >> timestamps ;
71+ private final Map <IndexCacheKey , ConcurrentMap < InternalFileIdentifier , Long >> timestamps ;
7072
7173 private static final Logger log = LoggerFactory .getLogger (IndexCacheOnDiscDeltaBased .class );
7274
@@ -106,7 +108,8 @@ public <T extends IndexCacheable> void store(IndexCacheKey cacheKey, String[] fi
106108 persist (cacheKey , new DeltaSnapshot <T >(store ), false );
107109
108110 // update local timestamp cache
109- ConcurrentHashMap <String , Long > timestampMap = new ConcurrentHashMap <>(timestampedFiles );
111+ ConcurrentMap <InternalFileIdentifier , Long > timestampMap = timestampedFiles .entrySet ().stream ()
112+ .collect (Collectors .toConcurrentMap (e -> InternalFileIdentifier .fromPath (e .getKey ()), e -> e .getValue ()));
110113 this .timestamps .put (cacheKey , timestampMap );
111114 }
112115
@@ -143,7 +146,9 @@ public <T extends IndexCacheable> Pair<T[], Multimap<String, String>> retrieve(I
143146 }
144147
145148 // update local timestamp cache
146- this .timestamps .put (cacheKey , new ConcurrentHashMap <>(timestampedFiles ));
149+ ConcurrentMap <InternalFileIdentifier , Long > timestampMap = timestampedFiles .entrySet ().stream ()
150+ .collect (Collectors .toConcurrentMap (e -> InternalFileIdentifier .fromPath (e .getKey ()), e -> e .getValue ()));
151+ this .timestamps .put (cacheKey , timestampMap );
147152
148153 return Pair .of (
149154 (T []) symbols .toArray ((T []) Array .newInstance (type , symbols .size ())),
@@ -168,10 +173,10 @@ public <T extends IndexCacheable> void removeFiles(IndexCacheKey cacheKey, Strin
168173 persist (cacheKey , new DeltaDelete <T >(files ), true );
169174
170175 // update local timestamp cache
171- Map <String , Long > timestampsMap = this .timestamps .get (cacheKey );
176+ Map <InternalFileIdentifier , Long > timestampsMap = this .timestamps .get (cacheKey );
172177 if (timestampsMap != null ) {
173178 for (String file : files ) {
174- timestampsMap .remove (file );
179+ timestampsMap .remove (InternalFileIdentifier . fromPath ( file ) );
175180 }
176181 }
177182 }
@@ -205,8 +210,8 @@ public <T extends IndexCacheable> void update(IndexCacheKey cacheKey, String fil
205210 persist (cacheKey , new DeltaUpdate <T >(deltaStore ), true );
206211
207212 // update local timestamp cache
208- Map <String , Long > timestampsMap = this .timestamps .computeIfAbsent (cacheKey , (s ) -> new ConcurrentHashMap <>());
209- timestampsMap .put (file , lastModified );
213+ Map <InternalFileIdentifier , Long > timestampsMap = this .timestamps .computeIfAbsent (cacheKey , (s ) -> new ConcurrentHashMap <>());
214+ timestampsMap .put (InternalFileIdentifier . fromPath ( file ) , lastModified );
210215 }
211216
212217 @ Override
@@ -229,17 +234,19 @@ public <T extends IndexCacheable> void update(IndexCacheKey cacheKey, String[] f
229234 persist (cacheKey , new DeltaUpdate <T >(deltaStore ), true );
230235
231236 // update local timestamp cache
232- Map <String , Long > timestampsMap = this .timestamps .computeIfAbsent (cacheKey , (s ) -> new ConcurrentHashMap <>());
237+ Map <InternalFileIdentifier , Long > timestampsMap = this .timestamps .computeIfAbsent (cacheKey , (s ) -> new ConcurrentHashMap <>());
233238 for (int i = 0 ; i < files .length ; i ++) {
234- timestampsMap .put (files [i ], lastModified [i ]);
239+ timestampsMap .put (InternalFileIdentifier . fromPath ( files [i ]) , lastModified [i ]);
235240 }
236241 }
237242
238243 @ Override
239244 public long getModificationTimestamp (IndexCacheKey cacheKey , String file ) {
240- Map <String , Long > timestampsMap = this .timestamps .get (cacheKey );
245+ InternalFileIdentifier fileID = InternalFileIdentifier .fromPath (file );
246+
247+ Map <InternalFileIdentifier , Long > timestampsMap = this .timestamps .get (cacheKey );
241248 if (timestampsMap != null ) {
242- Long result = timestampsMap .get (file );
249+ Long result = timestampsMap .get (fileID );
243250 if (result != null ) {
244251 return result ;
245252 }
@@ -335,12 +342,106 @@ public static Gson createGson() {
335342 .create ();
336343 }
337344
345+
346+ /**
347+ * just keep a md5 hash internally for identifying files to save memory
348+ */
349+ private static class InternalFileIdentifier {
350+
351+ public static InternalFileIdentifier fromPath (String fileName ) {
352+ byte [] id = DigestUtils .md5 (fileName );
353+ return new InternalFileIdentifier ( id );
354+ }
355+
356+ private byte [] id ;
357+
358+ private InternalFileIdentifier (byte [] id ) {
359+ this .id = id ;
360+ }
361+
362+ @ Override
363+ public int hashCode () {
364+ return Arrays .hashCode (id );
365+ }
366+
367+ @ Override
368+ public boolean equals (Object obj ) {
369+ if (this == obj )
370+ return true ;
371+ if (obj == null )
372+ return false ;
373+ if (getClass () != obj .getClass ())
374+ return false ;
375+ InternalFileIdentifier other = (InternalFileIdentifier ) obj ;
376+ return Arrays .equals (id , other .id );
377+ }
378+
379+ }
380+
381+
382+
383+
384+ /**
385+ * internal storage structure
386+ */
387+ private static class IndexCacheStore <T extends IndexCacheable > {
388+
389+ @ SuppressWarnings ("unused" )
390+ private final String elementType ;
391+
392+ private final SortedMap <String , Long > timestampedFiles ;
393+ private final List <T > elements ;
394+ private final Map <String , Collection <String >> dependencies ;
395+
396+ public IndexCacheStore (SortedMap <String , Long > timestampedFiles , List <T > elements , Map <String , Collection <String >> dependencies , Class <T > elementType ) {
397+ this .timestampedFiles = timestampedFiles ;
398+ this .elements = elements ;
399+ this .dependencies = dependencies ;
400+ this .elementType = elementType .getName ();
401+ }
402+
403+ public Map <String , Collection <String >> getDependencies () {
404+ return dependencies ;
405+ }
406+
407+ public List <T > getSymbols () {
408+ return elements ;
409+ }
410+
411+ public SortedMap <String , Long > getTimestampedFiles () {
412+ return timestampedFiles ;
413+ }
414+
415+ }
416+
417+
418+ //
419+ //
420+ // internal delta-based storage structure: snapshots, updates, and deletions
421+ //
422+ //
423+
424+
338425 private static record DeltaStorage <T extends IndexCacheable > (DeltaElement <T > storedElement ) {}
339426
340427 private static interface DeltaElement <T extends IndexCacheable > {
341428 public IndexCacheStore <T > apply (IndexCacheStore <T > store );
342429 }
343430
431+ private static class DeltaSnapshot <T extends IndexCacheable > implements DeltaElement <T > {
432+
433+ private IndexCacheStore <T > store ;
434+
435+ public DeltaSnapshot (IndexCacheStore <T > store ) {
436+ this .store = store ;
437+ }
438+
439+ @ Override
440+ public IndexCacheStore <T > apply (IndexCacheStore <T > store ) {
441+ return this .store ;
442+ }
443+ }
444+
344445 private static class DeltaDelete <T extends IndexCacheable > implements DeltaElement <T > {
345446
346447 private final String [] files ;
@@ -433,53 +534,12 @@ public IndexCacheStore<T> apply(IndexCacheStore<T> store) {
433534
434535 }
435536
436- private static class DeltaSnapshot <T extends IndexCacheable > implements DeltaElement <T > {
437-
438- private IndexCacheStore <T > store ;
439-
440- public DeltaSnapshot (IndexCacheStore <T > store ) {
441- this .store = store ;
442- }
443-
444- @ Override
445- public IndexCacheStore <T > apply (IndexCacheStore <T > store ) {
446- return this .store ;
447- }
448- }
449-
450-
451- /**
452- * internal storage structure
453- */
454- private static class IndexCacheStore <T extends IndexCacheable > {
455-
456- @ SuppressWarnings ("unused" )
457- private final String elementType ;
458537
459- private final SortedMap <String , Long > timestampedFiles ;
460- private final List <T > elements ;
461- private final Map <String , Collection <String >> dependencies ;
462-
463- public IndexCacheStore (SortedMap <String , Long > timestampedFiles , List <T > elements , Map <String , Collection <String >> dependencies , Class <T > elementType ) {
464- this .timestampedFiles = timestampedFiles ;
465- this .elements = elements ;
466- this .dependencies = dependencies ;
467- this .elementType = elementType .getName ();
468- }
469-
470- public Map <String , Collection <String >> getDependencies () {
471- return dependencies ;
472- }
473-
474- public List <T > getSymbols () {
475- return elements ;
476- }
477-
478- public SortedMap <String , Long > getTimestampedFiles () {
479- return timestampedFiles ;
480- }
481-
482- }
538+ //
539+ //
540+ // GSON serialize / deserialize adapters for the various types involved here that have special needs around JSON
541+ //
542+ //
483543
484544 private static class IndexCacheStoreAdapter implements JsonDeserializer <IndexCacheStore <?>> {
485545
0 commit comments