Skip to content

Commit 36334d3

Browse files
authored
Merge pull request #2582 from idodeclare/feature/history_ctags
Support ctags for historical revisions
2 parents 968004c + e861a90 commit 36334d3

31 files changed

+810
-431
lines changed

dev/checkstyle/suppressions.xml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
<?xml version="1.0"?>
2+
<!--
23
4+
CDDL HEADER START
5+
6+
The contents of this file are subject to the terms of the
7+
Common Development and Distribution License (the "License").
8+
You may not use this file except in compliance with the License.
9+
10+
See LICENSE.txt included in this distribution for the specific
11+
language governing permissions and limitations under the License.
12+
13+
When distributing Covered Code, include this CDDL HEADER in each
14+
file and include the License file at LICENSE.txt.
15+
If applicable, add the following below this CDDL HEADER, with the
16+
fields enclosed by brackets "[]" replaced with your own identifying
17+
information: Portions Copyright [yyyy] [name of copyright owner]
18+
19+
CDDL HEADER END
20+
21+
Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
22+
Portions Copyright (c) 2018, Chris Fraire <[email protected]>.
23+
24+
-->
325
<!DOCTYPE suppressions PUBLIC
426
"-//Checkstyle//DTD SuppressionFilter Configuration 1.1//EN"
527
"https://checkstyle.org/dtds/suppressions_1_1.dtd">
@@ -9,7 +31,8 @@
931
|CustomExactPhraseScorer\.java|PhrasePositions\.java|PhraseQueue\.java|Summarizer\.java|
1032
|Summary\.java|OGKUnifiedHighlighter\.java|ResponseHeaderFilter\.java|BoundedBlockingObjectPool\.java|
1133
|ObjectPool\.java|ObjectValidator\.java|ObjectFactory\.java|AbstractObjectPool\.java|
12-
|BlockingObjectPool\.java|OGKTextVecField\.java|OGKTextField\.java" />
34+
|BlockingObjectPool\.java|OGKTextVecField\.java|OGKTextField\.java|
35+
|LazilyInstantiate\.java" />
1336

1437
<suppress checks="ParameterNumber" files="CtagsReader\.java|Definitions\.java|PerlLexHelper\.java|
1538
|JFlexXrefUtils\.java|RubyLexHelper\.java|FileAnalyzerFactory\.java|SearchController\.java|

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public final class Configuration {
107107
* Path to {@code ctags} binary.
108108
*/
109109
private String ctags;
110+
private boolean webappCtags;
110111

111112
/**
112113
* A defined value to specify the mandoc binary or else null so that mandoc
@@ -475,6 +476,7 @@ public Configuration() {
475476
// unconditionally later.
476477
setUserPageSuffix("");
477478
setWebappLAF("default");
479+
// webappCtags is default(boolean)
478480
}
479481

480482
public String getRepoCmd(String clazzName) {
@@ -983,6 +985,20 @@ public void setWebappLAF(String webappLAF) {
983985
this.webappLAF = webappLAF;
984986
}
985987

988+
/**
989+
* Gets a value indicating if the web app should run ctags as necessary.
990+
*/
991+
public boolean isWebappCtags() {
992+
return webappCtags;
993+
}
994+
995+
/**
996+
* Sets a value indicating if the web app should run ctags as necessary.
997+
*/
998+
public void setWebappCtags(boolean value) {
999+
this.webappCtags = value;
1000+
}
1001+
9861002
public RemoteSCM getRemoteScmSupported() {
9871003
return remoteScmSupported;
9881004
}

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

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import java.util.concurrent.ExecutorService;
4444
import java.util.concurrent.Executors;
4545
import java.util.concurrent.ThreadFactory;
46-
import java.util.concurrent.TimeUnit;
4746
import java.util.concurrent.locks.Lock;
4847
import java.util.concurrent.locks.ReentrantReadWriteLock;
4948
import java.util.logging.Level;
@@ -65,9 +64,11 @@
6564
import org.opengrok.indexer.index.Filter;
6665
import org.opengrok.indexer.index.IgnoredNames;
6766
import org.opengrok.indexer.index.IndexDatabase;
67+
import org.opengrok.indexer.index.IndexerParallelizer;
6868
import org.opengrok.indexer.logger.LoggerFactory;
6969
import org.opengrok.indexer.util.CtagsUtil;
7070
import org.opengrok.indexer.util.ForbiddenSymlinkException;
71+
import org.opengrok.indexer.util.LazilyInstantiate;
7172
import org.opengrok.indexer.util.PathUtils;
7273
import org.opengrok.indexer.web.Prefix;
7374
import org.opengrok.indexer.web.Statistics;
@@ -88,11 +89,10 @@ public final class RuntimeEnvironment {
8889
private static final String URL_PREFIX = "/source" + Prefix.SEARCH_R + "?";
8990

9091
private Configuration configuration;
91-
private ReentrantReadWriteLock configLock;
92+
private final ReentrantReadWriteLock configLock;
93+
private final LazilyInstantiate<IndexerParallelizer> lzIndexerParallelizer;
94+
private final LazilyInstantiate<ExecutorService> lzSearchExecutor;
9295
private static final RuntimeEnvironment instance = new RuntimeEnvironment();
93-
private static ExecutorService historyExecutor = null;
94-
private static ExecutorService historyRenamedExecutor = null;
95-
private static ExecutorService searchExecutor = null;
9696

9797
private final Map<Project, List<RepositoryInfo>> repository_map = new ConcurrentHashMap<>();
9898
private final Map<String, SearcherManager> searcherManagerMap = new ConcurrentHashMap<>();
@@ -127,43 +127,21 @@ private RuntimeEnvironment() {
127127
configuration = new Configuration();
128128
configLock = new ReentrantReadWriteLock();
129129
watchDog = new WatchDogService();
130+
lzIndexerParallelizer = LazilyInstantiate.using(() ->
131+
new IndexerParallelizer(this));
132+
lzSearchExecutor = LazilyInstantiate.using(() -> newSearchExecutor());
130133
}
131134

132135
/** Instance of authorization framework.*/
133136
private AuthorizationFramework authFramework;
134137

135-
/* Get thread pool used for top-level repository history generation. */
136-
public static synchronized ExecutorService getHistoryExecutor() {
137-
if (historyExecutor == null) {
138-
historyExecutor = Executors.newFixedThreadPool(getInstance().getHistoryParallelism(),
139-
runnable -> {
140-
Thread thread = Executors.defaultThreadFactory().newThread(runnable);
141-
thread.setName("history-handling-" + thread.getId());
142-
return thread;
143-
});
144-
}
145-
146-
return historyExecutor;
147-
}
148-
149-
/* Get thread pool used for history generation of renamed files. */
150-
public static synchronized ExecutorService getHistoryRenamedExecutor() {
151-
if (historyRenamedExecutor == null) {
152-
historyRenamedExecutor = Executors.newFixedThreadPool(getInstance().getHistoryRenamedParallelism(),
153-
runnable -> {
154-
Thread thread = Executors.defaultThreadFactory().newThread(runnable);
155-
thread.setName("renamed-handling-" + thread.getId());
156-
return thread;
157-
});
158-
}
159-
160-
return historyRenamedExecutor;
138+
/** Gets the thread pool used for multi-project searches. */
139+
public ExecutorService getSearchExecutor() {
140+
return lzSearchExecutor.get();
161141
}
162142

163-
/* Get thread pool used for multi-project searches. */
164-
public synchronized ExecutorService getSearchExecutor() {
165-
if (searchExecutor == null) {
166-
searchExecutor = Executors.newFixedThreadPool(
143+
private ExecutorService newSearchExecutor() {
144+
return Executors.newFixedThreadPool(
167145
this.getMaxSearchThreadCount(),
168146
new ThreadFactory() {
169147
@Override
@@ -173,23 +151,6 @@ public Thread newThread(Runnable runnable) {
173151
return thread;
174152
}
175153
});
176-
}
177-
178-
return searchExecutor;
179-
}
180-
181-
public static synchronized void freeHistoryExecutor() {
182-
historyExecutor = null;
183-
}
184-
185-
public static synchronized void destroyRenamedHistoryExecutor() throws InterruptedException {
186-
if (historyRenamedExecutor != null) {
187-
historyRenamedExecutor.shutdown();
188-
// All the jobs should be completed by now however for testing
189-
// we would like to make sure the threads are gone.
190-
historyRenamedExecutor.awaitTermination(1, TimeUnit.MINUTES);
191-
historyRenamedExecutor = null;
192-
}
193154
}
194155

195156
/**
@@ -203,6 +164,10 @@ public static RuntimeEnvironment getInstance() {
203164

204165
public WatchDogService watchDog;
205166

167+
public IndexerParallelizer getIndexerParallelizer() {
168+
return lzIndexerParallelizer.get();
169+
}
170+
206171
private String getCanonicalPath(String s) {
207172
if (s == null) { return null; }
208173
try {
@@ -1092,6 +1057,14 @@ public void setWebappLAF(String laf) {
10921057
setConfigurationValue("webappLAF", laf);
10931058
}
10941059

1060+
/**
1061+
* Gets a value indicating if the web app should run ctags as necessary.
1062+
* @return the value of {@link Configuration#isWebappCtags()}
1063+
*/
1064+
public boolean isWebappCtags() {
1065+
return (boolean)getConfigurationValue("webappCtags");
1066+
}
1067+
10951068
public Configuration.RemoteSCM getRemoteScmSupported() {
10961069
return (Configuration.RemoteSCM)getConfigurationValue("remoteScmSupported");
10971070
}

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,13 @@
1919

2020
/*
2121
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
22+
* Portions Copyright (c) 2018, Chris Fraire <[email protected]>.
2223
*/
2324
package org.opengrok.indexer.history;
2425

2526
import java.io.BufferedReader;
26-
import java.io.ByteArrayInputStream;
2727
import java.io.File;
2828
import java.io.IOException;
29-
import java.io.InputStream;
3029
import java.nio.file.Files;
3130
import java.nio.file.Paths;
3231
import java.nio.file.Path;
@@ -38,6 +37,7 @@
3837
import java.util.regex.Pattern;
3938
import org.opengrok.indexer.configuration.RuntimeEnvironment;
4039
import org.opengrok.indexer.logger.LoggerFactory;
40+
import org.opengrok.indexer.util.BufferSink;
4141
import org.opengrok.indexer.util.Executor;
4242

4343
/**
@@ -165,10 +165,10 @@ Executor getHistoryLogExecutor(File file) throws IOException {
165165
}
166166

167167
@Override
168-
InputStream getHistoryGet(String parent, String basename, String rev) {
168+
boolean getHistoryGet(
169+
BufferSink sink, String parent, String basename, String rev) {
169170

170171
ArrayList<String> cmd = new ArrayList<>();
171-
InputStream inputStream = null;
172172
File directory = new File(parent);
173173

174174
/*
@@ -216,12 +216,16 @@ InputStream getHistoryGet(String parent, String basename, String rev) {
216216

217217
executor = new Executor(cmd, directory);
218218
executor.exec();
219-
220-
inputStream
221-
= new ByteArrayInputStream(executor.getOutputString().getBytes());
219+
try {
220+
copyBytes(sink, executor.getOutputStream());
221+
return true;
222+
} catch (IOException e) {
223+
LOGGER.log(Level.SEVERE, "Failed to obtain content for {0}",
224+
basename);
225+
}
222226
}
223227

224-
return inputStream;
228+
return false;
225229
}
226230

227231
@Override

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

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,20 @@
1919

2020
/*
2121
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
22-
* Portions Copyright (c) 2017, Chris Fraire <[email protected]>.
22+
* Portions Copyright (c) 2017-2018, Chris Fraire <[email protected]>.
2323
*/
2424
package org.opengrok.indexer.history;
2525

26-
import java.io.ByteArrayInputStream;
27-
import java.io.ByteArrayOutputStream;
2826
import java.io.File;
2927
import java.io.IOException;
30-
import java.io.InputStream;
3128
import java.util.ArrayList;
3229
import java.util.List;
3330
import java.util.TreeSet;
3431
import java.util.logging.Level;
3532
import java.util.logging.Logger;
3633
import org.opengrok.indexer.configuration.RuntimeEnvironment;
3734
import org.opengrok.indexer.logger.LoggerFactory;
35+
import org.opengrok.indexer.util.BufferSink;
3836
import org.opengrok.indexer.util.Executor;
3937

4038
/**
@@ -96,31 +94,19 @@ Executor getHistoryLogExecutor(final File file, final String sinceRevision)
9694
}
9795

9896
@Override
99-
public InputStream getHistoryGet(String parent, String basename, String rev) {
100-
InputStream ret = null;
97+
boolean getHistoryGet(
98+
BufferSink sink, String parent, String basename, String rev) {
10199

102100
File directory = new File(getDirectoryName());
103-
104101
Process process = null;
105102
try {
106103
String filename = (new File(parent, basename)).getCanonicalPath()
107104
.substring(getDirectoryName().length() + 1);
108105
ensureCommand(CMD_PROPERTY_KEY, CMD_FALLBACK);
109106
String[] argv = {RepoCommand, "cat", "-r", rev, filename};
110107
process = Runtime.getRuntime().exec(argv, null, directory);
111-
112-
ByteArrayOutputStream out = new ByteArrayOutputStream();
113-
byte[] buffer = new byte[32 * 1024];
114-
InputStream in = process.getInputStream();
115-
int len;
116-
117-
while ((len = in.read(buffer)) != -1) {
118-
if (len > 0) {
119-
out.write(buffer, 0, len);
120-
}
121-
}
122-
123-
ret = new ByteArrayInputStream(out.toByteArray());
108+
copyBytes(sink, process.getInputStream());
109+
return true;
124110
} catch (Exception exp) {
125111
LOGGER.log(Level.SEVERE,
126112
"Failed to get history: " + exp.getClass().toString(), exp);
@@ -136,7 +122,7 @@ public InputStream getHistoryGet(String parent, String basename, String rev) {
136122
}
137123
}
138124

139-
return ret;
125+
return false;
140126
}
141127

142128
/**

0 commit comments

Comments
 (0)