GH-1118: update cache once for multiple files being deleted

This commit is contained in:
Martin Lippert
2023-10-13 18:22:14 +02:00
parent 667a46b229
commit 6f7f9fdaf3
8 changed files with 148 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2020 Pivotal, Inc.
* Copyright (c) 2019, 2023 Pivotal, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -30,6 +30,7 @@ public interface IndexCache {
void remove(IndexCacheKey cacheKey);
<T extends IndexCacheable> void removeFile(IndexCacheKey symbolCacheKey, String file, Class<T> type);
<T extends IndexCacheable> void removeFiles(IndexCacheKey symbolCacheKey, String[] files, Class<T> type);
default <T extends IndexCacheable> T[] retrieveSymbols(IndexCacheKey cacheKey, String[] files, Class<T> type) {
Pair<T[], Multimap<String, String>> r = retrieve(cacheKey, files, type);

View File

@@ -168,6 +168,33 @@ public class IndexCacheOnDisc implements IndexCache {
}
}
@Override
public <T extends IndexCacheable> void removeFiles(IndexCacheKey cacheKey, String[] files, Class<T> type) {
@SuppressWarnings("unchecked")
IndexCacheStore<T> cacheStore = (IndexCacheStore<T>) this.stores.get(cacheKey);
if (cacheStore != null) {
SortedMap<String, Long> timestampedFiles = new TreeMap<>(cacheStore.getTimestampedFiles());
Map<String, Collection<String>> changedDeps = new HashMap<>(cacheStore.getDependencies());
Set<String> docURIs = new HashSet<>();
for (String file : files) {
String docURI = UriUtil.toUri(new File(file)).toASCIIString();
docURIs.add(docURI);
timestampedFiles.remove(file);
changedDeps.remove(file);
}
List<T> cachedSymbols = cacheStore.getSymbols().stream()
.filter(cachedSymbol -> !docURIs.contains(cachedSymbol.getDocURI()))
.collect(Collectors.toList());
save(cacheKey, cachedSymbols, timestampedFiles, changedDeps, type);
}
}
@Override
public void remove(IndexCacheKey cacheKey) {
File cacheStore = new File(cacheDirectory, cacheKey.toString() + ".json");

View File

@@ -47,6 +47,10 @@ public class IndexCacheVoid implements IndexCache {
public <T extends IndexCacheable> void removeFile(IndexCacheKey symbolCacheKey, String file, Class<T> type) {
}
@Override
public <T extends IndexCacheable> void removeFiles(IndexCacheKey symbolCacheKey, String[] files, Class<T> type) {
}
@Override
public long getModificationTimestamp(IndexCacheKey cacheKey, String docURI) {
return 0;

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -284,11 +285,16 @@ public class SpringFactoriesIndexer implements SpringIndexer {
@Override
public void removeFiles(IJavaProject project, String[] docURIs) throws Exception {
String[] files = Arrays.stream(docURIs).map(docURI -> {
try {
return new File(new URI(docURI)).getAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}).toArray(String[]::new);
IndexCacheKey key = getCacheKey(project);
for (String docUri : docURIs) {
String file = new File(new URI(docUri)).getAbsolutePath();
cache.removeFile(key, file, CachedSymbol.class);
}
cache.removeFiles(key, files, CachedSymbol.class);
}
}

View File

@@ -199,17 +199,22 @@ public class SpringIndexerJava implements SpringIndexer {
@Override
public void removeFiles(IJavaProject project, String[] docURIs) throws Exception {
String[] files = Arrays.stream(docURIs).map(docURI -> {
try {
return new File(new URI(docURI)).getAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}).toArray(String[]::new);
IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY);
IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY);
IndexCacheKey diagnosticsCacheKey = getCacheKey(project, DIAGNOSTICS_KEY);
for (String docURI : docURIs) {
String file = new File(new URI(docURI)).getAbsolutePath();
this.cache.removeFile(symbolsCacheKey, file, CachedSymbol.class);
this.cache.removeFile(beansCacheKey, file, CachedBean.class);
this.cache.removeFile(diagnosticsCacheKey, file, CachedDiagnostics.class);
}
this.cache.removeFiles(symbolsCacheKey, files, CachedSymbol.class);
this.cache.removeFiles(beansCacheKey, files, CachedBean.class);
this.cache.removeFiles(diagnosticsCacheKey, files, CachedDiagnostics.class);
}
private DocumentDescriptor[] filterDocuments(IJavaProject project, DocumentDescriptor[] updatedDocs) {

View File

@@ -13,6 +13,7 @@ package org.springframework.ide.vscode.boot.java.utils;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -212,15 +213,19 @@ public class SpringIndexerXML implements SpringIndexer {
@Override
public void removeFiles(IJavaProject project, String[] docURIs) throws Exception {
String[] files = Arrays.stream(docURIs).map(docURI -> {
try {
return new File(new URI(docURI)).getAbsolutePath();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}).toArray(String[]::new);
IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY);
IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY);
for (String docURI : docURIs) {
String file = new File(new URI(docURI)).getAbsolutePath();
this.cache.removeFile(symbolsCacheKey, file, CachedSymbol.class);
this.cache.removeFile(beansCacheKey, file, CachedBean.class);
}
this.cache.removeFiles(symbolsCacheKey, files, CachedSymbol.class);
this.cache.removeFiles(beansCacheKey, files, CachedBean.class);
}
private void scanFile(IJavaProject project, String fileName, List<CachedSymbol> generatedSymbols, List<CachedBean> generatedBeans) {

View File

@@ -621,4 +621,82 @@ public class IndexCacheOnDiscTest {
assertEquals(ImmutableSet.of(), cachedDependencies.get(file1.toString()));
assertEquals(ImmutableSet.of("dep2"), cachedDependencies.get(file2.toString()));
}
@Test
void testMultipleFilesDeleted() throws Exception {
Path file1 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile1");
Path file2 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile2");
Path file3 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile3");
Path file4 = Paths.get(tempDir.toAbsolutePath().toString(), "tempFile4");
Files.createFile(file1);
Files.createFile(file2);
Files.createFile(file3);
Files.createFile(file4);
FileTime timeFile1 = Files.getLastModifiedTime(file1);
FileTime timeFile2 = Files.getLastModifiedTime(file2);
FileTime timeFile3 = Files.getLastModifiedTime(file3);
FileTime timeFile4 = Files.getLastModifiedTime(file4);
String[] files = {
file1.toAbsolutePath().toString(),
file2.toAbsolutePath().toString(),
file3.toAbsolutePath().toString(),
file4.toAbsolutePath().toString()
};
String doc1URI = UriUtil.toUri(file1.toFile()).toASCIIString();
String doc2URI = UriUtil.toUri(file2.toFile()).toASCIIString();
String doc3URI = UriUtil.toUri(file3.toFile()).toASCIIString();
String doc4URI = UriUtil.toUri(file4.toFile()).toASCIIString();
List<CachedSymbol> generatedSymbols = new ArrayList<>();
WorkspaceSymbol symbol1 = new WorkspaceSymbol("symbol1", SymbolKind.Field, Either.forLeft(new Location(doc1URI, new Range(new Position(3, 10), new Position(3, 20)))));
EnhancedSymbolInformation enhancedSymbol1 = new EnhancedSymbolInformation(symbol1, null);
WorkspaceSymbol symbol2 = new WorkspaceSymbol("symbol2", SymbolKind.Field, Either.forLeft(new Location(doc2URI, new Range(new Position(5, 10), new Position(5, 20)))));
EnhancedSymbolInformation enhancedSymbol2 = new EnhancedSymbolInformation(symbol2, null);
WorkspaceSymbol symbol3 = new WorkspaceSymbol("symbol3", SymbolKind.Field, Either.forLeft(new Location(doc3URI, new Range(new Position(20, 11), new Position(20, 30)))));
EnhancedSymbolInformation enhancedSymbol3 = new EnhancedSymbolInformation(symbol3, null);
WorkspaceSymbol symbol4 = new WorkspaceSymbol("symbol4", SymbolKind.Field, Either.forLeft(new Location(doc4URI, new Range(new Position(4, 4), new Position(5, 5)))));
EnhancedSymbolInformation enhancedSymbol4 = new EnhancedSymbolInformation(symbol4, null);
generatedSymbols.add(new CachedSymbol(doc1URI, timeFile1.toMillis(), enhancedSymbol1));
generatedSymbols.add(new CachedSymbol(doc2URI, timeFile2.toMillis(), enhancedSymbol2));
generatedSymbols.add(new CachedSymbol(doc3URI, timeFile3.toMillis(), enhancedSymbol3));
generatedSymbols.add(new CachedSymbol(doc4URI, timeFile4.toMillis(), enhancedSymbol4));
Multimap<String, String> dependencies = ImmutableMultimap.of(
file1.toString(), "dep1",
file2.toString(), "dep2"
);
cache.store(CACHE_KEY_VERSION_1, files, generatedSymbols, dependencies, CachedSymbol.class);
// cache.removeFile(CACHE_KEY_VERSION_1, file1.toAbsolutePath().toString(), CachedSymbol.class);
// cache.removeFile(CACHE_KEY_VERSION_1, file3.toAbsolutePath().toString(), CachedSymbol.class);
cache.removeFiles(CACHE_KEY_VERSION_1, new String[] {file1.toAbsolutePath().toString(), file3.toAbsolutePath().toString()}, CachedSymbol.class);
files = new String[]{file2.toAbsolutePath().toString(), file4.toAbsolutePath().toString()};
Pair<CachedSymbol[], Multimap<String, String>> result = cache.retrieve(CACHE_KEY_VERSION_1, files, CachedSymbol.class);
CachedSymbol[] cachedSymbols = result.getLeft();
assertNotNull(result);
assertEquals(2, cachedSymbols.length);
assertEquals("symbol2", cachedSymbols[0].getEnhancedSymbol().getSymbol().getName());
assertEquals(SymbolKind.Field, cachedSymbols[0].getEnhancedSymbol().getSymbol().getKind());
assertEquals(new Location(doc2URI, new Range(new Position(5, 10), new Position(5, 20))), cachedSymbols[0].getEnhancedSymbol().getSymbol().getLocation().getLeft());
assertNull(cachedSymbols[0].getEnhancedSymbol().getAdditionalInformation());
assertEquals("symbol4", cachedSymbols[1].getEnhancedSymbol().getSymbol().getName());
assertEquals(SymbolKind.Field, cachedSymbols[1].getEnhancedSymbol().getSymbol().getKind());
assertEquals(new Location(doc4URI, new Range(new Position(4, 4), new Position(5, 5))), cachedSymbols[1].getEnhancedSymbol().getSymbol().getLocation().getLeft());
assertNull(cachedSymbols[1].getEnhancedSymbol().getAdditionalInformation());
Multimap<String, String> cachedDependencies = result.getRight();
assertEquals(ImmutableSet.of(), cachedDependencies.get(file1.toString()));
assertEquals(ImmutableSet.of("dep2"), cachedDependencies.get(file2.toString()));
}
}

View File

@@ -85,6 +85,10 @@ public class IndexCacheTimestampsOnly implements IndexCache {
public <T extends IndexCacheable> void removeFile(IndexCacheKey symbolCacheKey, String file, Class<T> type) {
}
@Override
public <T extends IndexCacheable> void removeFiles(IndexCacheKey symbolCacheKey, String[] files, Class<T> type) {
}
@Override
public long getModificationTimestamp(IndexCacheKey cacheKey, String file) {
Map<String, Long> timestampMap = timestampCache.get(cacheKey);