Skip to content

Commit 3434df0

Browse files
author
Vladimir Kotal
authored
log merged/written revisions in FileHistoryCache (#3826)
* log merged/written revisions * revert the condition to original semantics * adjust the comment * no need for square brackets * split the logging * use isLoggable() * fix review comment * leverage Repository.toString() * make toString() report more info about the repository * add missing fields to the copy constructor
1 parent 731916a commit 3434df0

File tree

5 files changed

+86
-40
lines changed

5 files changed

+86
-40
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ public Set<String> getCtagsLanguages() {
659659
/**
660660
* Get the max time a SCM operation may use to avoid being cached.
661661
*
662-
* @return the max time
662+
* @return the maximum time in milliseconds
663663
*/
664664
public int getHistoryReaderTimeLimit() {
665665
return syncReadConfiguration(Configuration::getHistoryCacheTime);

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

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,19 @@ static History readCache(File file) throws IOException {
245245
* @param cacheFile the file to store the history to
246246
*/
247247
private void writeHistoryToFile(File dir, History history, File cacheFile) throws HistoryException {
248+
249+
if (LOGGER.isLoggable(Level.FINEST)) {
250+
LOGGER.log(Level.FINEST, "writing history entries to ''{0}'': {1}",
251+
new Object[]{cacheFile, history.getRevisionList()});
252+
}
253+
248254
// We have a problem that multiple threads may access the cache layer
249255
// at the same time. Since I would like to avoid read-locking, I just
250256
// serialize the write access to the cache file. The generation of the
251257
// cache file would most likely be executed during index generation, and
252-
// that happens sequencial anyway....
258+
// that happens sequential anyway....
253259
// Generate the file with a temporary name and move it into place when
254-
// I'm done so I don't have to protect the readers for partially updated
260+
// done, so it is not necessary to protect the readers for partially updated
255261
// files...
256262
final File output;
257263
try {
@@ -305,19 +311,23 @@ private History mergeOldAndNewHistory(File cacheFile, History histNew, Repositor
305311
// Merge old history with the new history.
306312
List<HistoryEntry> listOld = histOld.getHistoryEntries();
307313
if (!listOld.isEmpty()) {
314+
if (LOGGER.isLoggable(Level.FINEST)) {
315+
LOGGER.log(Level.FINEST, "for ''{0}'' merging old history {1} with new history {2}",
316+
new Object[]{cacheFile, histOld.getRevisionList(), histNew.getRevisionList()});
317+
}
308318
List<HistoryEntry> listNew = histNew.getHistoryEntries();
309319
ListIterator<HistoryEntry> li = listNew.listIterator(listNew.size());
310320
while (li.hasPrevious()) {
311321
listOld.add(0, li.previous());
312322
}
313323
history = new History(listOld);
314324

315-
// Retag the changesets in case there have been some new
325+
// Re-tag the changesets in case there have been some new
316326
// tags added to the repository. Technically we should just
317-
// retag the last revision from the listOld however this
327+
// re-tag the last revision from the listOld however this
318328
// does not solve the problem when listNew contains new tags
319-
// retroactively tagging changesets from listOld so we resort
320-
// to this somewhat crude solution of retagging from scratch.
329+
// retroactively tagging changesets from listOld, so we resort
330+
// to this somewhat crude solution of re-tagging from scratch.
321331
if (env.isTagsEnabled() && repo.hasFileBasedTags()) {
322332
history.strip();
323333
repo.assignTagsInHistory(history);
@@ -361,16 +371,16 @@ private void storeFile(History histNew, File file, Repository repo, boolean merg
361371
}
362372

363373
// If the merge failed, null history will be returned.
364-
// In such case store at least new history as a best effort.
374+
// In such case store at least new history as the best effort.
365375
if (history == null) {
376+
LOGGER.log(Level.WARNING, "history cache for file ''{0}'' truncated to new history", file);
366377
history = histNew;
367378
}
368379

369380
writeHistoryToFile(dir, history, cacheFile);
370381
}
371382

372-
private void storeFile(History histNew, File file, Repository repo)
373-
throws HistoryException {
383+
private void storeFile(History histNew, File file, Repository repo) throws HistoryException {
374384
storeFile(histNew, file, repo, false);
375385
}
376386

@@ -382,7 +392,7 @@ private void finishStore(Repository repository, String latestRev) {
382392
// create confusion (once it starts working again).
383393
LOGGER.log(Level.WARNING,
384394
"Could not store history for repository {0}: {1} is not a directory",
385-
new Object[]{repository.getDirectoryName(), histDir});
395+
new Object[]{repository, histDir});
386396
} else {
387397
storeLatestCachedRevision(repository, latestRev);
388398
}
@@ -495,7 +505,7 @@ public void store(History history, Repository repository, String tillRevision) t
495505
* The renamed files will be handled separately.
496506
*/
497507
LOGGER.log(Level.FINE, "Storing history for {0} regular files in repository ''{1}'' till {2}",
498-
new Object[]{regularFiles.size(), repository.getDirectoryName(), getRevisionString(tillRevision)});
508+
new Object[]{regularFiles.size(), repository, getRevisionString(tillRevision)});
499509
final File root = env.getSourceRootFile();
500510

501511
final CountDownLatch latch = new CountDownLatch(regularFiles.size());
@@ -526,7 +536,7 @@ public void store(History history, Repository repository, String tillRevision) t
526536
LOGGER.log(Level.SEVERE, "latch exception", ex);
527537
}
528538
LOGGER.log(Level.FINE, "Stored history for {0} regular files in repository ''{1}''",
529-
new Object[]{fileHistoryCount, repository.getDirectoryName()});
539+
new Object[]{fileHistoryCount, repository});
530540
}
531541

532542
if (!handleRenamedFiles) {
@@ -554,7 +564,7 @@ public void storeRenamed(Set<String> renamedFiles, Repository repository, String
554564
renamedFiles = renamedFiles.stream().filter(f -> new File(env.getSourceRootPath() + f).exists()).
555565
collect(Collectors.toSet());
556566
LOGGER.log(Level.FINE, "Storing history for {0} renamed files in repository ''{1}'' till {2}",
557-
new Object[]{renamedFiles.size(), repository.getDirectoryName(), getRevisionString(tillRevision)});
567+
new Object[]{renamedFiles.size(), repository, getRevisionString(tillRevision)});
558568

559569
createDirectoriesForFiles(renamedFiles, repository, "renamed files for history " +
560570
getRevisionString(tillRevision));
@@ -592,7 +602,7 @@ public void storeRenamed(Set<String> renamedFiles, Repository repository, String
592602
}
593603
}
594604
LOGGER.log(Level.FINE, "Stored history for {0} renamed files in repository ''{1}''",
595-
new Object[]{renamedFileHistoryCount.intValue(), repository.getDirectoryName()});
605+
new Object[]{renamedFileHistoryCount.intValue(), repository});
596606
}
597607

598608
private void createDirectoriesForFiles(Set<String> files, Repository repository, String label)
@@ -625,22 +635,22 @@ private void createDirectoriesForFiles(Set<String> files, Repository repository,
625635
@Override
626636
public History get(File file, Repository repository, boolean withFiles)
627637
throws HistoryException, ForbiddenSymlinkException {
628-
File cache = getCachedFile(file);
629-
if (isUpToDate(file, cache)) {
638+
File cacheFile = getCachedFile(file);
639+
if (isUpToDate(file, cacheFile)) {
630640
try {
631641
if (fileHistoryCacheHits != null) {
632642
fileHistoryCacheHits.increment();
633643
}
634-
return readCache(cache);
644+
return readCache(cacheFile);
635645
} catch (Exception e) {
636-
LOGGER.log(Level.WARNING,
637-
"Error when reading cache file '" + cache, e);
646+
LOGGER.log(Level.WARNING, String.format("Error when reading cache file '%s'", cacheFile), e);
638647
}
639648
}
640649

641650
if (fileHistoryCacheMisses != null) {
642651
fileHistoryCacheMisses.increment();
643652
}
653+
644654
/*
645655
* Some mirrors of repositories which are capable of fetching history
646656
* for directories may contain lots of files untracked by given SCM.
@@ -666,21 +676,28 @@ public History get(File file, Repository repository, boolean withFiles)
666676
time = System.currentTimeMillis() - time;
667677
} catch (UnsupportedOperationException e) {
668678
// In this case, we've found a file for which the SCM has no history
669-
// An example is a non-SCCS file somewhere in an SCCS-controlled
670-
// workspace.
679+
// An example is a non-SCCS file somewhere in an SCCS-controlled workspace.
671680
return null;
672681
}
673682

683+
// Don't cache history-information for directories, since the
684+
// history information on the directory may change if a file in
685+
// a sub-directory change. This will cause us to present a stale
686+
// history log until the current directory is updated and
687+
// invalidates the cache entry.
674688
if (!file.isDirectory()) {
675-
// Don't cache history-information for directories, since the
676-
// history information on the directory may change if a file in
677-
// a sub-directory change. This will cause us to present a stale
678-
// history log until a the current directory is updated and
679-
// invalidates the cache entry.
680-
if ((cache != null) &&
681-
(cache.exists() ||
682-
(time > env.getHistoryReaderTimeLimit()))) {
683-
// retrieving the history takes too long, cache it!
689+
// Either the cache is stale or retrieving the history took too long, cache it!
690+
if (cacheFile.exists()) {
691+
if (LOGGER.isLoggable(Level.FINEST)) {
692+
LOGGER.log(Level.FINEST, "refreshing history for ''{0}'': {1}",
693+
new Object[]{file, history.getRevisionList()});
694+
}
695+
storeFile(history, file, repository);
696+
} else if (time > env.getHistoryReaderTimeLimit()) {
697+
if (LOGGER.isLoggable(Level.FINEST)) {
698+
LOGGER.log(Level.FINEST, "getting history for ''{0}'' took longer than {1} ms, caching it: {2}",
699+
new Object[]{file, env.getHistoryReaderTimeLimit(), history.getRevisionList()});
700+
}
684701
storeFile(history, file, repository);
685702
}
686703
}
@@ -714,11 +731,10 @@ public String getRepositoryHistDataDirname(Repository repository) {
714731
String repoDirBasename;
715732

716733
try {
717-
repoDirBasename = env.getPathRelativeToSourceRoot(
718-
new File(repository.getDirectoryName()));
734+
repoDirBasename = env.getPathRelativeToSourceRoot(new File(repository.getDirectoryName()));
719735
} catch (IOException ex) {
720-
LOGGER.log(Level.WARNING, "Could not resolve " +
721-
repository.getDirectoryName() + " relative to source root", ex);
736+
LOGGER.log(Level.WARNING,
737+
String.format("Could not resolve repository %s relative to source root", repository), ex);
722738
return null;
723739
} catch (ForbiddenSymlinkException ex) {
724740
LOGGER.log(Level.FINER, ex.getMessage());
@@ -751,8 +767,8 @@ private void storeLatestCachedRevision(Repository repository, String rev) {
751767
new FileOutputStream(getRepositoryCachedRevPath(repository))));
752768
writer.write(rev);
753769
} catch (IOException ex) {
754-
LOGGER.log(Level.WARNING, "Cannot write latest cached revision to file for " + repository.getDirectoryName(),
755-
ex);
770+
LOGGER.log(Level.WARNING,
771+
String.format("Cannot write latest cached revision to file for repository %s", repository), ex);
756772
} finally {
757773
try {
758774
if (writer != null) {
@@ -771,8 +787,7 @@ public String getLatestCachedRevision(Repository repository) {
771787

772788
String revPath = getRepositoryCachedRevPath(repository);
773789
if (revPath == null) {
774-
LOGGER.log(Level.WARNING, "no rev path for {0}",
775-
repository.getDirectoryName());
790+
LOGGER.log(Level.WARNING, "no rev path for repository {0}", repository);
776791
return null;
777792
}
778793

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Map;
3333
import java.util.Objects;
3434
import java.util.Set;
35+
import java.util.stream.Collectors;
3536

3637
/**
3738
* Class representing the history of a file.
@@ -158,6 +159,14 @@ public Set<String> getRenamedFiles() {
158159
return renamedFiles;
159160
}
160161

162+
/**
163+
* @return list of revisions
164+
*/
165+
public List<String> getRevisionList() {
166+
return getHistoryEntries().stream().
167+
map(HistoryEntry::getRevision).collect(Collectors.toList());
168+
}
169+
161170
/**
162171
* Strip files and tags.
163172
* @see HistoryEntry#strip()

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,26 @@ public abstract class Repository extends RepositoryInfo {
100100
abstract boolean hasHistoryForDirectories();
101101

102102
public String toString() {
103-
return this.getDirectoryName();
103+
StringBuilder stringBuilder = new StringBuilder();
104+
stringBuilder.append("{");
105+
stringBuilder.append("dir=");
106+
stringBuilder.append(this.getDirectoryName());
107+
stringBuilder.append(",");
108+
stringBuilder.append("type=");
109+
stringBuilder.append(getType());
110+
stringBuilder.append(",");
111+
112+
if (!isHistoryEnabled()) {
113+
stringBuilder.append("history=off");
114+
} else {
115+
stringBuilder.append("renamed=");
116+
stringBuilder.append(this.isHandleRenamedFiles());
117+
stringBuilder.append(",");
118+
stringBuilder.append("merge=");
119+
stringBuilder.append(this.isMergeCommitsEnabled());
120+
}
121+
stringBuilder.append("}");
122+
return stringBuilder.toString();
104123
}
105124

106125
/**

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ public RepositoryInfo(RepositoryInfo orig) {
9696
this.parent = orig.parent;
9797
this.branch = orig.branch;
9898
this.currentVersion = orig.currentVersion;
99+
this.historyEnabled = orig.historyEnabled;
100+
this.handleRenamedFiles = orig.handleRenamedFiles;
101+
this.mergeCommitsEnabled = orig.mergeCommitsEnabled;
99102
}
100103

101104
/**

0 commit comments

Comments
 (0)