Skip to content

Commit d091b4b

Browse files
committed
make removeFile() smarter
fixes #1701
1 parent 31a8348 commit d091b4b

File tree

3 files changed

+169
-48
lines changed

3 files changed

+169
-48
lines changed

src/org/opensolaris/opengrok/index/IndexChangedListener.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/*
21-
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
21+
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
2222
*/
2323
package org.opensolaris.opengrok.index;
2424

@@ -35,7 +35,7 @@ public interface IndexChangedListener {
3535
*/
3636
void fileAdd(String path, String analyzer);
3737
/**
38-
* A file is to be added to the index database
38+
* A file was added to the index database
3939
* @param path The path to the file (absolute from source root)
4040
* @param analyzer The analyzer being used to analyze the file
4141
*/
@@ -46,7 +46,7 @@ public interface IndexChangedListener {
4646
*/
4747
void fileRemove(String path);
4848
/**
49-
* A file is to be removed from the index database
49+
* A file was removed from the index database
5050
* @param path The path to the file (absolute from source root)
5151
*/
5252
void fileRemoved(String path);

src/org/opensolaris/opengrok/index/IndexDatabase.java

Lines changed: 68 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,39 @@ public boolean addDirectory(String dir) {
311311
return false;
312312
}
313313

314+
private int getFileCount(File sourceRoot, String dir) throws IOException {
315+
int file_cnt = 0;
316+
if (RuntimeEnvironment.getInstance().isPrintProgress()) {
317+
LOGGER.log(Level.INFO, "Counting files in {0} ...", dir);
318+
file_cnt = indexDown(sourceRoot, dir, true, 0, 0);
319+
LOGGER.log(Level.INFO,
320+
"Need to process: {0} files for {1}",
321+
new Object[]{file_cnt, dir});
322+
}
323+
324+
return file_cnt;
325+
}
326+
327+
private void markProjectIndexed(Project project) throws IOException {
328+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
329+
330+
// Successfully indexed the directory. If this is a project
331+
// that has just been indexed for the first time mark it so
332+
// by sending special message to the webapp.
333+
if (project != null && !project.isIndexed()) {
334+
if (env.getConfigHost() != null && env.getConfigPort() > 0) {
335+
Message m = Message.createMessage("project");
336+
m.addTag(project.getName());
337+
m.setText("indexed");
338+
m.write(env.getConfigHost(), env.getConfigPort());
339+
}
340+
341+
// Also need to store the correct value in configuration
342+
// when indexer writes it to a file.
343+
project.setIndexed(true);
344+
}
345+
}
346+
314347
/**
315348
* Update the content of this index database
316349
*
@@ -337,7 +370,7 @@ public void update() throws IOException, HistoryException {
337370
}
338371

339372
if (ctags != null) {
340-
String filename = RuntimeEnvironment.getInstance().getCTagsExtraOptionsFile();
373+
String filename = env.getCTagsExtraOptionsFile();
341374
if (filename != null) {
342375
ctags.setCTagsExtraOptionsFile(filename);
343376
}
@@ -391,44 +424,22 @@ public void update() throws IOException, HistoryException {
391424
startuid);
392425
}
393426
}
394-
// The code below traverses the tree to get total count.
395-
int file_cnt = 0;
396-
if (env.isPrintProgress()) {
397-
LOGGER.log(Level.INFO, "Counting files in {0} ...", dir);
398-
file_cnt = indexDown(sourceRoot, dir, true, 0, 0);
399-
LOGGER.log(Level.INFO,
400-
"Need to process: {0} files for {1}",
401-
new Object[]{file_cnt, dir});
402-
}
403427

404428
// The actual indexing happens in indexDown().
405-
indexDown(sourceRoot, dir, false, 0, file_cnt);
429+
indexDown(sourceRoot, dir, false, 0,
430+
getFileCount(sourceRoot, dir));
406431

407432
while (uidIter != null && uidIter.term() != null
408433
&& uidIter.term().utf8ToString().startsWith(startuid)) {
409434

410-
removeFile();
435+
removeFile(true);
411436
BytesRef next = uidIter.next();
412-
if (next==null) {
437+
if (next == null) {
413438
uidIter=null;
414439
}
415440
}
416441

417-
// Successfully indexed the directory. If this is a project
418-
// that has just been indexed for the first time mark it so
419-
// by sending special message to the webapp.
420-
if (project != null && !project.isIndexed()) {
421-
if (env.getConfigHost() != null && env.getConfigPort() > 0) {
422-
Message m = Message.createMessage("project");
423-
m.addTag(project.getName());
424-
m.setText("indexed");
425-
m.write(env.getConfigHost(), env.getConfigPort());
426-
}
427-
428-
// Also need to store the correct value in configuration
429-
// when indexer writes it to a file.
430-
project.setIndexed(true);
431-
}
442+
markProjectIndexed(project);
432443
} finally {
433444
reader.close();
434445
}
@@ -602,9 +613,10 @@ private void removeHistoryFile(String path) {
602613
* Remove a stale file (uidIter.term().text()) from the index database,
603614
* history cache and xref.
604615
*
616+
* @param removeHistory if false, do not remove history cache for this file
605617
* @throws java.io.IOException if an error occurs
606618
*/
607-
private void removeFile() throws IOException {
619+
private void removeFile(boolean removeHistory) throws IOException {
608620
String path = Util.uid2url(uidIter.term().utf8ToString());
609621

610622
for (IndexChangedListener listener : listeners) {
@@ -616,7 +628,9 @@ private void removeFile() throws IOException {
616628
writer.commit();
617629

618630
removeXrefFile(path);
619-
removeHistoryFile(path);
631+
if (removeHistory) {
632+
removeHistoryFile(path);
633+
}
620634

621635
setDirty();
622636
for (IndexChangedListener listener : listeners) {
@@ -837,16 +851,25 @@ private boolean isLocal(String path) {
837851
return local;
838852
}
839853

854+
private void printProgress(int currentCount, int totalCount) {
855+
if (RuntimeEnvironment.getInstance().isPrintProgress()
856+
&& totalCount > 0 && LOGGER.isLoggable(Level.INFO)) {
857+
LOGGER.log(Level.INFO, "Progress: {0} ({1}%)",
858+
new Object[]{currentCount,
859+
(currentCount * 100.0f / totalCount)});
860+
}
861+
}
862+
840863
/**
841864
* Generate indexes recursively
842865
*
843866
* @param dir the root indexDirectory to generate indexes for
844-
* @param path the path
867+
* @param parent path to parent directory
845868
* @param count_only if true will just traverse the source root and count
846869
* files
847-
* @param cur_count current count during the traversal of the tree
870+
* @param cur_count current file count during the traversal of the tree
848871
* @param est_total estimate total files to process
849-
*
872+
* @return current file count
850873
*/
851874
private int indexDown(File dir, String parent, boolean count_only,
852875
int cur_count, int est_total) throws IOException {
@@ -880,30 +903,31 @@ private int indexDown(File dir, String parent, boolean count_only,
880903
continue;
881904
}
882905

883-
if (RuntimeEnvironment.getInstance().isPrintProgress()
884-
&& est_total > 0 && LOGGER.isLoggable(Level.INFO)) {
885-
LOGGER.log(Level.INFO, "Progress: {0} ({1}%)",
886-
new Object[]{lcur_count,
887-
(lcur_count * 100.0f / est_total)});
888-
}
906+
printProgress(lcur_count, est_total);
889907

890908
if (uidIter != null) {
891909
String uid = Util.path2uid(path,
892910
DateTools.timeToString(file.lastModified(),
893911
DateTools.Resolution.MILLISECOND)); // construct uid for doc
894-
BytesRef buid = new BytesRef(uid);
912+
BytesRef buid = new BytesRef(uid);
895913
while (uidIter != null && uidIter.term() != null
896-
&& uidIter.term().compareTo(emptyBR) !=0
914+
&& uidIter.term().compareTo(emptyBR) != 0
897915
&& uidIter.term().compareTo(buid) < 0) {
898-
removeFile();
916+
917+
String termPath = Util.uid2url(uidIter.term().utf8ToString());
918+
removeFile(!termPath.equals(path));
899919
BytesRef next = uidIter.next();
900-
if (next==null) {uidIter=null;}
920+
if (next == null) {
921+
uidIter = null;
922+
}
901923
}
902924

903925
if (uidIter != null && uidIter.term() != null
904926
&& uidIter.term().bytesEquals(buid)) {
905927
BytesRef next = uidIter.next(); // keep matching docs
906-
if (next==null) {uidIter=null;}
928+
if (next == null) {
929+
uidIter = null;
930+
}
907931
continue;
908932
}
909933
}

test/org/opensolaris/opengrok/index/IndexerTest.java

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
*/
2323
package org.opensolaris.opengrok.index;
2424

25+
import java.io.BufferedWriter;
2526
import java.io.File;
2627
import java.io.FileReader;
28+
import java.io.FileWriter;
2729
import java.io.IOException;
2830
import java.io.StringWriter;
2931
import java.util.ArrayList;
@@ -193,7 +195,7 @@ public void testMain() throws IOException {
193195
}
194196
}
195197

196-
private class MyIndexChangeListener implements org.opensolaris.opengrok.index.IndexChangedListener {
198+
private class MyIndexChangeListener implements IndexChangedListener {
197199

198200
List<String> files = new ArrayList<>();
199201
List<String> removedFiles = new ArrayList<>();
@@ -271,6 +273,101 @@ public void testIndexWithSetIndexVersionedFilesOnly() throws Exception {
271273
}
272274
}
273275

276+
/**
277+
* IndexChangedListener class used solely for {@code testRemoveFileOnFileChange()}.
278+
*/
279+
private class RemoveIndexChangeListener implements IndexChangedListener {
280+
281+
List<String> filesToAdd = new ArrayList<>();
282+
List<String> removedFiles = new ArrayList<>();
283+
284+
@Override
285+
public void fileAdd(String path, String analyzer) {
286+
filesToAdd.add(path);
287+
}
288+
289+
@Override
290+
public void fileAdded(String path, String analyzer) {
291+
}
292+
293+
@Override
294+
public void fileRemove(String path) {
295+
}
296+
297+
@Override
298+
public void fileUpdate(String path) {
299+
}
300+
301+
@Override
302+
public void fileRemoved(String path) {
303+
// The test for the file existence needs to be performed here
304+
// since the call to {@code removeFile()} will be eventually
305+
// followed by {@code addFile()} that will create the file again.
306+
if (path.equals("/mercurial/bar.txt")) {
307+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
308+
File f = new File(env.getDataRootPath(), "historycache" + path + ".gz");
309+
Assert.assertTrue("history cache file should be preserved", f.exists());
310+
}
311+
removedFiles.add(path);
312+
}
313+
314+
public void reset() {
315+
this.filesToAdd = new ArrayList<>();
316+
this.removedFiles = new ArrayList<>();
317+
}
318+
}
319+
320+
/**
321+
* Test that reindex after changing a file does not wipe out history index
322+
* for this file. This is important for the incremental history indexing.
323+
* @throws Exception
324+
*/
325+
@Test
326+
public void testRemoveFileOnFileChange() throws Exception {
327+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
328+
329+
env.setCtags(System.getProperty(ctagsProperty, "ctags"));
330+
if (!env.validateExuberantCtags()) {
331+
System.out.println("Skipping test due to no ctags");
332+
}
333+
334+
TestRepository testrepo = new TestRepository();
335+
testrepo.create(HistoryGuru.class.getResourceAsStream("repositories.zip"));
336+
337+
env.setSourceRoot(testrepo.getSourceRoot());
338+
env.setDataRoot(testrepo.getDataRoot());
339+
HistoryGuru.getInstance().addRepositories(testrepo.getSourceRoot());
340+
341+
// create index
342+
Project project = new Project("mercurial", "/mercurial");
343+
IndexDatabase idb = new IndexDatabase(project);
344+
assertNotNull(idb);
345+
RemoveIndexChangeListener listener = new RemoveIndexChangeListener();
346+
idb.addIndexChangedListener(listener);
347+
idb.update();
348+
Assert.assertEquals(5, listener.filesToAdd.size());
349+
listener.reset();
350+
351+
// Change a file so that it gets picked up by the indexer.
352+
File bar = new File(testrepo.getSourceRoot() + File.separator + "mercurial",
353+
"bar.txt");
354+
Assert.assertTrue(bar.exists());
355+
FileWriter fw = new FileWriter(bar, true);
356+
BufferedWriter bw = new BufferedWriter(fw);
357+
bw.write("foo\n");
358+
bw.close();
359+
fw.close();
360+
361+
// reindex
362+
idb.update();
363+
// Make sure that the file was actually processed.
364+
assertEquals(1, listener.removedFiles.size());
365+
assertEquals(1, listener.filesToAdd.size());
366+
assertEquals("/mercurial/bar.txt", listener.removedFiles.get(0));
367+
368+
testrepo.destroy();
369+
}
370+
274371
@Test
275372
public void testXref() throws IOException {
276373
List<File> files = new ArrayList<>();

0 commit comments

Comments
 (0)