Skip to content

Commit 94b68a3

Browse files
committed
HistoryGuru should perform repository fallback
1 parent 094a9b1 commit 94b68a3

File tree

5 files changed

+118
-146
lines changed

5 files changed

+118
-146
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/history/FileHistoryCache.java

Lines changed: 10 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
import io.micrometer.core.instrument.MeterRegistry;
6666
import org.jetbrains.annotations.Nullable;
6767
import org.jetbrains.annotations.TestOnly;
68+
import org.jetbrains.annotations.VisibleForTesting;
6869
import org.opengrok.indexer.Metrics;
6970
import org.opengrok.indexer.configuration.PathAccepter;
7071
import org.opengrok.indexer.configuration.RuntimeEnvironment;
@@ -89,21 +90,10 @@ class FileHistoryCache implements HistoryCache {
8990
private static final String LATEST_REV_FILE_NAME = "OpenGroklatestRev";
9091

9192
private final PathAccepter pathAccepter = env.getPathAccepter();
92-
private boolean historyIndexDone = false;
9393

9494
private Counter fileHistoryCacheHits;
9595
private Counter fileHistoryCacheMisses;
9696

97-
@Override
98-
public void setHistoryIndexDone() {
99-
historyIndexDone = true;
100-
}
101-
102-
@Override
103-
public boolean isHistoryIndexDone() {
104-
return historyIndexDone;
105-
}
106-
10797
/**
10898
* Generate history cache for single renamed file.
10999
* @param filename file path
@@ -214,8 +204,7 @@ private static File getCachedFile(File file) throws HistoryException, ForbiddenS
214204
}
215205
sb.append(add);
216206
} catch (IOException e) {
217-
throw new HistoryException("Failed to get path relative to " +
218-
"source root for " + file, e);
207+
throw new HistoryException("Failed to get path relative to source root for " + file, e);
219208
}
220209

221210
return new File(TandemPath.join(sb.toString(), ".gz"));
@@ -470,6 +459,11 @@ private static String getRevisionString(String revision) {
470459
* stored under this hierarchy, each file containing history of
471460
* corresponding source file.
472461
*
462+
* <p>
463+
* <b>Note that the history object will be changed in the process of storing the history into cache.
464+
* Namely the list of files from the history entries will be stripped.</b>
465+
* </p>
466+
*
473467
* @param history history object to process into per-file histories
474468
* @param repository repository object
475469
* @param tillRevision end revision (can be null)
@@ -641,13 +635,6 @@ private void createDirectoriesForFiles(Set<String> files, Repository repository,
641635
public History get(File file, Repository repository, boolean withFiles)
642636
throws HistoryException, ForbiddenSymlinkException {
643637

644-
return get(file, repository, withFiles, env.isFetchHistoryWhenNotInCache());
645-
}
646-
647-
@Override
648-
public History get(File file, Repository repository, boolean withFiles, boolean fallback)
649-
throws HistoryException, ForbiddenSymlinkException {
650-
651638
File cacheFile = getCachedFile(file);
652639
if (isUpToDate(file, cacheFile)) {
653640
try {
@@ -664,32 +651,7 @@ public History get(File file, Repository repository, boolean withFiles, boolean
664651
fileHistoryCacheMisses.increment();
665652
}
666653

667-
/*
668-
* Some mirrors of repositories which are capable of fetching history
669-
* for directories may contain lots of files untracked by given SCM.
670-
* For these it would be waste of time to get their history
671-
* since the history of all files in this repository should have been
672-
* fetched in the first phase of indexing.
673-
*/
674-
if (isHistoryIndexDone() && repository.isHistoryEnabled() && repository.hasHistoryForDirectories() &&
675-
!fallback) {
676-
return null;
677-
}
678-
679-
if (!pathAccepter.accept(file)) {
680-
return null;
681-
}
682-
683-
final History history;
684-
try {
685-
history = repository.getHistory(file);
686-
} catch (UnsupportedOperationException e) {
687-
// In this case, we've found a file for which the SCM has no history
688-
// An example is a non-SCCS file somewhere in an SCCS-controlled workspace.
689-
return null;
690-
}
691-
692-
return history;
654+
return null;
693655
}
694656

695657
/**
@@ -714,7 +676,8 @@ public boolean hasCacheForFile(File file) throws HistoryException {
714676
}
715677
}
716678

717-
public String getRepositoryHistDataDirname(Repository repository) {
679+
@VisibleForTesting
680+
public static String getRepositoryHistDataDirname(Repository repository) {
718681
String repoDirBasename;
719682

720683
try {

opengrok-indexer/src/main/java/org/opengrok/indexer/history/HistoryCache.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,10 @@ interface HistoryCache {
5757
* @param withFiles A flag saying whether the returned history should include a list of files
5858
* touched by each changeset. If false, the implementation is allowed to skip the file list,
5959
* but it doesn't have to.
60-
* @param fallback whether to fall back to {@link Repository#getHistory(File)}
61-
* if the history cannot be retrieved from the cache
6260
* @throws HistoryException if the history cannot be fetched
6361
* @throws ForbiddenSymlinkException if symbolic-link checking encounters
6462
* an ineligible link
6563
*/
66-
History get(File file, @Nullable Repository repository, boolean withFiles, boolean fallback)
67-
throws HistoryException, ForbiddenSymlinkException;
68-
69-
/**
70-
* Usually a wrapper of {@link HistoryCache#get(File, Repository, boolean, boolean)}.
71-
*/
7264
History get(File file, @Nullable Repository repository, boolean withFiles)
7365
throws HistoryException, ForbiddenSymlinkException;
7466

@@ -153,8 +145,4 @@ Map<String, Date> getLastModifiedTimes(File directory, Repository repository)
153145
* @throws HistoryException if an error occurred while getting the info
154146
*/
155147
String getInfo() throws HistoryException;
156-
157-
// Set and query if history index phase is done.
158-
void setHistoryIndexDone();
159-
boolean isHistoryIndexDone();
160148
}

opengrok-indexer/src/main/java/org/opengrok/indexer/history/HistoryGuru.java

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ public final class HistoryGuru {
9595
*/
9696
private final RepositoryLookup repositoryLookup;
9797

98+
private boolean historyIndexDone = false;
99+
100+
public void setHistoryIndexDone() {
101+
historyIndexDone = true;
102+
}
103+
104+
public boolean isHistoryIndexDone() {
105+
return historyIndexDone;
106+
}
107+
98108
/**
99109
* Creates a new instance of HistoryGuru, and try to set the default source
100110
* control system.
@@ -230,6 +240,16 @@ public History getHistoryUI(File file) throws HistoryException {
230240
return getHistory(file, true, true);
231241
}
232242

243+
/**
244+
* The idea is that some repositories require reaching out to remote server whenever
245+
* a history operation is done. Sometimes this is unwanted and this method decides that.
246+
* This should be consulted before the actual repository operation, i.e. not when fetching
247+
* history from a cache since that is inherently local operation.
248+
* @param repo repository
249+
* @param file file to decide the operation for
250+
* @param ui whether coming from UI
251+
* @return whether to perform the history operation
252+
*/
233253
boolean isRepoHistoryEligible(Repository repo, File file, boolean ui) {
234254
RemoteSCM rscm = env.getRemoteScmSupported();
235255
boolean doRemote = (ui && (rscm == RemoteSCM.UIONLY))
@@ -241,17 +261,19 @@ boolean isRepoHistoryEligible(Repository repo, File file, boolean ui) {
241261
}
242262

243263
@Nullable
244-
private History getHistoryFromCache(File file, Repository repository, boolean withFiles, boolean fallback)
264+
private History getHistoryFromCache(File file, Repository repository, boolean withFiles)
245265
throws HistoryException, ForbiddenSymlinkException {
246266

247267
if (useCache() && historyCache.supportsRepository(repository)) {
248-
return historyCache.get(file, repository, withFiles, fallback);
268+
return historyCache.get(file, repository, withFiles);
249269
}
250270

251271
return null;
252272
}
253273

254274
/**
275+
* Get last {@link HistoryEntry} for a file. First, try to retrieve it from the cache.
276+
* If that fails, fallback to the repository method.
255277
* @param file file to get the history entry for
256278
* @param ui is the request coming from the UI
257279
* @return last (newest) history entry for given file or {@code null}
@@ -264,15 +286,9 @@ public HistoryEntry getLastHistoryEntry(File file, boolean ui) throws HistoryExc
264286
final File dir = file.isDirectory() ? file : file.getParentFile();
265287
final Repository repository = getRepository(dir);
266288

267-
if (!isRepoHistoryEligible(repository, file, ui)) {
268-
LOGGER.log(Level.FINER, "cannot retrieve the last history entry for ''{0}'' in {1} because of settings",
269-
new Object[]{file, repository});
270-
return null;
271-
}
272-
273289
History history;
274290
try {
275-
history = getHistoryFromCache(file, repository, false, false);
291+
history = getHistoryFromCache(file, repository, false);
276292
if (history != null) {
277293
HistoryEntry lastHistoryEntry = history.getLastHistoryEntry();
278294
if (lastHistoryEntry != null) {
@@ -286,14 +302,21 @@ public HistoryEntry getLastHistoryEntry(File file, boolean ui) throws HistoryExc
286302
return null;
287303
}
288304

305+
if (!isRepoHistoryEligible(repository, file, ui)) {
306+
LOGGER.log(Level.FINER, "cannot retrieve the last history entry for ''{0}'' in {1} because of settings",
307+
new Object[]{file, repository});
308+
return null;
309+
}
310+
311+
// Fallback to the repository method.
289312
HistoryEntry lastHistoryEntry = repository.getLastHistoryEntry(file, ui);
290313
if (lastHistoryEntry != null) {
291314
LOGGER.log(Level.FINEST, "got latest history entry {0} for ''{1}'' using repository {2}",
292315
new Object[]{lastHistoryEntry, file, repository});
293316
}
294317
statistics.report(LOGGER, Level.FINEST,
295318
String.format("finished retrieval of last history entry for '%s' (%s)",
296-
file, lastHistoryEntry != null ? "success" : "fail"), "history.lasthistoryentry");
319+
file, lastHistoryEntry != null ? "success" : "fail"), "history.entry.latest");
297320
return lastHistoryEntry;
298321
}
299322

@@ -318,22 +341,52 @@ public History getHistory(File file, boolean withFiles, boolean ui, boolean fall
318341
final File dir = file.isDirectory() ? file : file.getParentFile();
319342
final Repository repository = getRepository(dir);
320343

321-
if (!isRepoHistoryEligible(repository, file, ui)) {
322-
return null;
323-
}
324-
325344
History history;
326345
try {
327-
history = getHistoryFromCache(file, repository, withFiles, fallback);
346+
history = getHistoryFromCache(file, repository, withFiles);
328347
if (history != null) {
329348
return history;
330349
}
350+
351+
return getHistoryFromRepository(file, repository, ui);
331352
} catch (ForbiddenSymlinkException e) {
332353
LOGGER.log(Level.FINER, e.getMessage());
333354
return null;
334355
}
356+
}
335357

336-
return null;
358+
@Nullable
359+
private History getHistoryFromRepository(File file, Repository repository, boolean ui) throws HistoryException {
360+
History history;
361+
362+
if (!isRepoHistoryEligible(repository, file, ui)) {
363+
return null;
364+
}
365+
366+
/*
367+
* Some mirrors of repositories which are capable of fetching history
368+
* for directories may contain lots of files untracked by given SCM.
369+
* For these it would be waste of time to get their history
370+
* since the history of all files in this repository should have been
371+
* fetched in the first phase of indexing.
372+
*/
373+
if (isHistoryIndexDone() && repository.isHistoryEnabled() && repository.hasHistoryForDirectories()) {
374+
return null;
375+
}
376+
377+
if (!env.getPathAccepter().accept(file)) {
378+
return null;
379+
}
380+
381+
try {
382+
history = repository.getHistory(file);
383+
} catch (UnsupportedOperationException e) {
384+
// In this case, we've found a file for which the SCM has no history
385+
// An example is a non-SCCS file somewhere in an SCCS-controlled workspace.
386+
return null;
387+
}
388+
389+
return history;
337390
}
338391

339392
/**
@@ -684,7 +737,7 @@ private void createCacheReal(Collection<Repository> repositories) {
684737
"Failed optimizing the history cache database", he);
685738
}
686739
elapsed.report(LOGGER, "Done history cache for all repositories", "indexer.history.cache");
687-
historyCache.setHistoryIndexDone();
740+
setHistoryIndexDone();
688741
}
689742

690743
/**

0 commit comments

Comments
 (0)