Skip to content

Commit d93fdca

Browse files
authored
use history cache dates in directory listing for regular files (#4275)
fixes #4087
1 parent 6c299e7 commit d93fdca

File tree

17 files changed

+322
-106
lines changed

17 files changed

+322
-106
lines changed

opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/Configuration.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ public final class Configuration {
306306

307307
private boolean historyBasedReindex;
308308

309+
private boolean useHistoryCacheForDirectoryListing;
310+
309311
/**
310312
* History handling types for remote SCM repositories.
311313
* <ul>
@@ -544,12 +546,14 @@ public Configuration() {
544546
setAllowLeadingWildcard(true);
545547
setAllowedSymlinks(new HashSet<>());
546548
setAnnotationCacheEnabled(false);
549+
setApiTimeout(300); // 5 minutes
547550
setAuthenticationTokens(new HashSet<>());
548551
setAuthorizationWatchdogEnabled(false);
549552
//setBugPage("http://bugs.myserver.org/bugdatabase/view_bug.do?bug_id=");
550553
setBugPattern("\\b([12456789][0-9]{6})\\b");
551554
setCachePages(5);
552555
setCanonicalRoots(new HashSet<>());
556+
setConnectTimeout(10);
553557
setIndexerCommandTimeout(600); // 10 minutes
554558
setRestfulCommandTimeout(60);
555559
setInteractiveCommandTimeout(30);
@@ -568,6 +572,7 @@ public Configuration() {
568572
setGroups(new TreeSet<>());
569573
setGroupsCollapseThreshold(4);
570574
setHandleHistoryOfRenamedFiles(false);
575+
setHistoryBasedReindex(true);
571576
setHistoryCache(true);
572577
setHistoryEnabled(true);
573578
setHitsPerPage(25);
@@ -602,15 +607,13 @@ public Configuration() {
602607
setSourceRoot(null);
603608
//setTabSize(4);
604609
setTagsEnabled(false);
610+
setUseHistoryCacheForDirectoryListing(true);
605611
//setUserPage("http://www.myserver.org/viewProfile.jspa?username=");
606-
// Set to empty string so we can append it to the URL unconditionally later.
607-
setHistoryBasedReindex(true);
612+
// Set to empty string, so we can append it to the URL unconditionally later.
608613
setUserPageSuffix("");
609614
setWebappLAF("default");
610615
// webappCtags is default(boolean)
611616
setXrefTimeout(30);
612-
setApiTimeout(300); // 5 minutes
613-
setConnectTimeout(10);
614617
}
615618

616619
public String getRepoCmd(String clazzName) {
@@ -1462,6 +1465,14 @@ public void setHistoryBasedReindex(boolean flag) {
14621465
historyBasedReindex = flag;
14631466
}
14641467

1468+
public boolean isUseHistoryCacheForDirectoryListing() {
1469+
return useHistoryCacheForDirectoryListing;
1470+
}
1471+
1472+
public void setUseHistoryCacheForDirectoryListing(boolean flag) {
1473+
useHistoryCacheForDirectoryListing = flag;
1474+
}
1475+
14651476
/**
14661477
* Write the current configuration to a file.
14671478
*

opengrok-indexer/src/main/java/org/opengrok/indexer/configuration/RuntimeEnvironment.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,14 @@ public void setHistoryBasedReindex(boolean flag) {
14991499
syncWriteConfiguration(flag, Configuration::setHistoryBasedReindex);
15001500
}
15011501

1502+
public boolean isUseHistoryCacheForDirectoryListing() {
1503+
return syncReadConfiguration(Configuration::isUseHistoryCacheForDirectoryListing);
1504+
}
1505+
1506+
public void setUseHistoryCacheForDirectoryListing(boolean flag) {
1507+
syncWriteConfiguration(flag, Configuration::setUseHistoryCacheForDirectoryListing);
1508+
}
1509+
15021510
public FileCollector getFileCollector(String projectName) {
15031511
return fileCollectorMap.get(projectName);
15041512
}

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import java.nio.file.Path;
4141
import java.util.ArrayList;
4242
import java.util.Collections;
43-
import java.util.Date;
4443
import java.util.HashMap;
4544
import java.util.Iterator;
4645
import java.util.List;
@@ -66,6 +65,7 @@
6665
import org.opengrok.indexer.configuration.PathAccepter;
6766
import org.opengrok.indexer.configuration.RuntimeEnvironment;
6867
import org.opengrok.indexer.logger.LoggerFactory;
68+
import org.opengrok.indexer.search.DirectoryEntry;
6969
import org.opengrok.indexer.util.Progress;
7070
import org.opengrok.indexer.util.Statistics;
7171

@@ -666,7 +666,7 @@ public History get(File file, Repository repository, boolean withFiles) throws C
666666
fileHistoryCacheHits.increment();
667667
}
668668
return readHistory(cacheFile, repository);
669-
} catch (Exception e) {
669+
} catch (IOException e) {
670670
LOGGER.log(Level.WARNING, String.format("Error when reading cache file '%s'", cacheFile), e);
671671
}
672672
}
@@ -679,6 +679,7 @@ public History get(File file, Repository repository, boolean withFiles) throws C
679679
}
680680

681681
@Override
682+
@Nullable
682683
public HistoryEntry getLastHistoryEntry(File file) throws CacheException {
683684
if (isUpToDate(file)) {
684685
File cacheFile = getCachedFile(file);
@@ -687,7 +688,7 @@ public HistoryEntry getLastHistoryEntry(File file) throws CacheException {
687688
fileHistoryCacheHits.increment();
688689
}
689690
return readLastHistoryEntry(cacheFile);
690-
} catch (Exception e) {
691+
} catch (IOException e) {
691692
LOGGER.log(Level.WARNING, String.format("Error when reading cache file '%s'", cacheFile), e);
692693
}
693694
}
@@ -771,11 +772,32 @@ private String getCachedRevision(Repository repository, String revPath) {
771772
}
772773

773774
@Override
774-
public Map<String, Date> getLastModifiedTimes(File directory, Repository repository) {
775-
// We don't have a good way to get this information from the file
776-
// cache, so leave it to the caller to find a reasonable time to
777-
// display (typically the last modified time on the file system).
778-
return Collections.emptyMap();
775+
public Map<String, HistoryEntry> getLastHistoryEntries(List<DirectoryEntry> entries) {
776+
if (entries == null) {
777+
return Collections.emptyMap();
778+
}
779+
780+
Map<String, HistoryEntry> map = new HashMap<>();
781+
for (DirectoryEntry directoryEntry : entries) {
782+
try {
783+
File file = directoryEntry.getFile();
784+
if (file.isDirectory()) {
785+
continue;
786+
}
787+
788+
HistoryEntry historyEntry = getLastHistoryEntry(file);
789+
if (historyEntry != null && historyEntry.getDate() != null) {
790+
map.put(directoryEntry.getFile().getName(), historyEntry);
791+
} else {
792+
LOGGER.log(Level.FINE, "cannot get last history entry for ''{0}''",
793+
directoryEntry.getFile());
794+
}
795+
} catch (CacheException e) {
796+
LOGGER.log(Level.FINER, "cannot get last history entry for ''{0}''", directoryEntry.getFile());
797+
}
798+
}
799+
800+
return map;
779801
}
780802

781803
@Override

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ public GitRepository() {
110110
ignoredFiles.add(".git");
111111
}
112112

113+
@Override
114+
public boolean isMergeCommitsSupported() {
115+
return true;
116+
}
117+
113118
/**
114119
* Be careful, git uses only forward slashes in its command and output (not in file path).
115120
* Using backslashes together with git show will get empty output and 0 status code.

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
package org.opengrok.indexer.history;
2424

2525
import java.io.File;
26-
import java.util.Date;
26+
import java.util.List;
2727
import java.util.Map;
2828

2929
import org.jetbrains.annotations.Nullable;
30+
import org.opengrok.indexer.search.DirectoryEntry;
3031

3132
interface HistoryCache extends Cache {
3233

@@ -49,6 +50,7 @@ interface HistoryCache extends Cache {
4950
* @param file The file to retrieve history for
5051
* @throws CacheException if the history cache cannot be read
5152
*/
53+
@Nullable
5254
HistoryEntry getLastHistoryEntry(File file) throws CacheException;
5355

5456
/**
@@ -93,12 +95,11 @@ interface HistoryCache extends Cache {
9395
* Get the last modified times for all files and subdirectories in the
9496
* specified directory.
9597
*
96-
* @param directory which directory to fetch modification times for
97-
* @param repository the repository in which the directory lives
98-
* @return a map from file names to modification times
98+
* @param entries list of {@link DirectoryEntry} instances
99+
* @return a map from file names to {@link HistoryEntry} instance
99100
* @throws CacheException on error
100101
*/
101-
Map<String, Date> getLastModifiedTimes(File directory, Repository repository) throws CacheException;
102+
Map<String, HistoryEntry> getLastHistoryEntries(List<DirectoryEntry> entries) throws CacheException;
102103

103104
/**
104105
* Clear entry for single file from history cache.

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,17 @@ public void dump() {
123123
new Object[]{separator, file});
124124
separator = ">";
125125
}
126-
}
126+
}
127+
128+
/**
129+
* @return description of selected fields; used in the web app.
130+
*/
131+
@JsonIgnore
132+
public String getDescription() {
133+
return "changeset: " + getRevision()
134+
+ "\nsummary: " + getMessage() + "\nuser: "
135+
+ getAuthor() + "\ndate: " + getDate();
136+
}
127137

128138
public String getAuthor() {
129139
return author;

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.ArrayList;
3232
import java.util.Collection;
3333
import java.util.Collections;
34-
import java.util.Date;
3534
import java.util.HashMap;
3635
import java.util.List;
3736
import java.util.Map;
@@ -55,6 +54,7 @@
5554
import org.opengrok.indexer.configuration.PathAccepter;
5655
import org.opengrok.indexer.configuration.RuntimeEnvironment;
5756
import org.opengrok.indexer.logger.LoggerFactory;
57+
import org.opengrok.indexer.search.DirectoryEntry;
5858
import org.opengrok.indexer.util.ForbiddenSymlinkException;
5959
import org.opengrok.indexer.util.PathUtils;
6060
import org.opengrok.indexer.util.Statistics;
@@ -337,9 +337,7 @@ private void completeAnnotationWithHistory(File file, Annotation annotation, Rep
337337
String hist_rev = he.getRevision();
338338
String short_rev = repo.getRevisionForAnnotate(hist_rev);
339339
if (revs.contains(short_rev)) {
340-
annotation.addDesc(short_rev, "changeset: " + he.getRevision()
341-
+ "\nsummary: " + he.getMessage() + "\nuser: "
342-
+ he.getAuthor() + "\ndate: " + he.getDate());
340+
annotation.addDesc(short_rev, he.getDescription());
343341
// History entries are coming from recent to older,
344342
// file version should be from oldest to newer.
345343
annotation.addFileVersion(short_rev, revs.size() - revsMatched);
@@ -714,13 +712,21 @@ public boolean hasAnnotationCacheForFile(File file) {
714712

715713
/**
716714
* Get the last modified times for all files and subdirectories in the specified directory.
717-
*
715+
* If the related {@link Repository} instance does not exist or if it is capable or merge commits,
716+
* however merge commits are disabled in its properties, empty map will be returned.
718717
* @param directory the directory whose files to check
719-
* @return a map from file names to modification times for the files that
718+
* @param entries list of {@link DirectoryEntry} instances
719+
* @return a map from file names to {@link HistoryEntry} instance for the files that
720720
* the history cache has information about
721721
* @throws org.opengrok.indexer.history.CacheException if history cannot be retrieved
722722
*/
723-
public Map<String, Date> getLastModifiedTimes(File directory) throws CacheException {
723+
public Map<String, HistoryEntry> getLastHistoryEntries(File directory, List<DirectoryEntry> entries) throws CacheException {
724+
725+
if (!env.isUseHistoryCacheForDirectoryListing()) {
726+
LOGGER.log(Level.FINEST, "using history cache to retrieve last modified times for ''{0}}'' is disabled",
727+
directory);
728+
return Collections.emptyMap();
729+
}
724730

725731
Repository repository = getRepository(directory);
726732
if (repository == null) {
@@ -729,13 +735,23 @@ public Map<String, Date> getLastModifiedTimes(File directory) throws CacheExcept
729735
return Collections.emptyMap();
730736
}
731737

738+
// Do not use history cache for repositories with merge commits disabled as some files in the repository
739+
// could be introduced and changed solely via merge changesets. The call would presumably fall back
740+
// to file system based time stamps, however that might be confusing, so avoid that.
741+
if (repository.isMergeCommitsSupported() && !repository.isMergeCommitsEnabled()) {
742+
LOGGER.log(Level.FINEST,
743+
"will not retrieve last modified times due to merge changesets disabled for ''{0}}''",
744+
directory);
745+
return Collections.emptyMap();
746+
}
747+
732748
if (!useHistoryCache()) {
733749
LOGGER.log(Level.FINEST, "history cache is disabled for ''{0}'' to retrieve last modified times",
734750
directory);
735751
return Collections.emptyMap();
736752
}
737753

738-
return historyCache.getLastModifiedTimes(directory, repository);
754+
return historyCache.getLastHistoryEntries(entries);
739755
}
740756

741757
/**

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ public MercurialRepository() {
129129
ignoredDirs.add(".hg");
130130
}
131131

132+
@Override
133+
public boolean isMergeCommitsSupported() {
134+
return true;
135+
}
136+
132137
/**
133138
* Return name of the branch or "default".
134139
*/

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ public void setHandleRenamedFiles(boolean flag) {
127127
this.handleRenamedFiles = flag;
128128
}
129129

130+
/**
131+
* Default implementation, should be overridden by individual repository implementations.
132+
* @return whether merge commits are supported
133+
*/
134+
public boolean isMergeCommitsSupported() {
135+
return false;
136+
}
137+
130138
/**
131139
* @return true if the repository handles merge commits.
132140
*/
@@ -430,6 +438,9 @@ public String toString() {
430438
stringBuilder.append("historyCache=on,");
431439
stringBuilder.append("renamed=");
432440
stringBuilder.append(this.isHandleRenamedFiles());
441+
}
442+
443+
if (isMergeCommitsSupported()) {
433444
stringBuilder.append(",");
434445
stringBuilder.append("merge=");
435446
stringBuilder.append(this.isMergeCommitsEnabled());

opengrok-indexer/src/main/java/org/opengrok/indexer/web/Util.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -735,7 +735,7 @@ private static void writeAnnotation(int num, Writer out, Annotation annotation,
735735
out.write("<span class=\"blame\">");
736736
if (enabled) {
737737
out.write(ANCHOR_CLASS_START);
738-
out.write("r");
738+
out.write("r title-tooltip");
739739
out.write("\" style=\"background-color: ");
740740
out.write(annotation.getColors().getOrDefault(r, "inherit"));
741741
out.write("\" href=\"");

0 commit comments

Comments
 (0)