Skip to content

Commit 848d3b8

Browse files
committed
Add PendingFileCompleter, and use during Lucene 2-phase commit
1 parent 48bd3b3 commit 848d3b8

File tree

4 files changed

+442
-30
lines changed

4 files changed

+442
-30
lines changed

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

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,17 @@ public class IndexDatabase {
9696

9797
private static final Logger LOGGER = LoggerFactory.getLogger(IndexDatabase.class);
9898

99+
/**
100+
* Formerly, every delete issued an IndexWriter commit(). This is a first
101+
* draft of a policy value used to flush -- not commit -- deleted Lucene
102+
* items periodically.
103+
*/
104+
private static final int MAX_BUFFERED_DELETE_TERMS = 200;
105+
99106
private Project project;
100107
private FSDirectory indexDirectory;
101108
private IndexWriter writer;
109+
private PendingFileCompleter completer;
102110
private TermsEnum uidIter;
103111
private IgnoredNames ignoredNames;
104112
private Filter includedNames;
@@ -377,14 +385,16 @@ public void update() throws IOException, HistoryException {
377385
}
378386
}
379387

380-
IOException writerException = null;
388+
IOException finishingException = null;
381389
try {
382390
Analyzer analyzer = AnalyzerGuru.getAnalyzer();
383391
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
384392
iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
385393
iwc.setRAMBufferSizeMB(env.getRamBufferSize());
394+
iwc.setMaxBufferedDeleteTerms(MAX_BUFFERED_DELETE_TERMS);
386395
writer = new IndexWriter(indexDirectory, iwc);
387396
writer.commit(); // to make sure index exists on the disk
397+
completer = new PendingFileCompleter();
388398

389399
if (directories.isEmpty()) {
390400
if (project == null) {
@@ -451,20 +461,19 @@ public void update() throws IOException, HistoryException {
451461
}
452462

453463
try {
454-
writer.commit();
464+
finishWriting();
455465
} catch (IOException e) {
456-
writerException = e;
457-
LOGGER.log(Level.WARNING,
458-
"An error occured while committing writer", e);
466+
finishingException = e;
459467
}
460468
} finally {
461469
Ctags finishingCtags = ctags;
462470
ctags = null;
463471

472+
completer = null;
464473
try {
465474
if (writer != null) writer.close();
466475
} catch (IOException e) {
467-
if (writerException == null) writerException = e;
476+
if (finishingException == null) finishingException = e;
468477
LOGGER.log(Level.WARNING,
469478
"An error occured while closing writer", e);
470479
} finally {
@@ -484,7 +493,7 @@ public void update() throws IOException, HistoryException {
484493
}
485494
}
486495

487-
if (writerException != null) throw writerException;
496+
if (finishingException != null) throw finishingException;
488497

489498
if (!isInterrupted() && isDirty()) {
490499
if (env.isOptimizeDatabase()) {
@@ -604,7 +613,7 @@ private void setDirty() {
604613
}
605614

606615
/**
607-
* Remove xref file for given path
616+
* Queue the removal of xref file for given path
608617
* @param path path to file under source root
609618
*/
610619
private void removeXrefFile(String path) {
@@ -614,18 +623,9 @@ private void removeXrefFile(String path) {
614623
} else {
615624
xrefFile = new File(xrefDir, path);
616625
}
617-
File parent = xrefFile.getParentFile();
618-
619-
if (!xrefFile.delete() && xrefFile.exists()) {
620-
LOGGER.log(Level.INFO, "Failed to remove obsolete xref-file: {0}",
621-
xrefFile.getAbsolutePath());
622-
}
623-
624-
// Remove the parent directory if it's empty.
625-
if (parent.delete()) {
626-
LOGGER.log(Level.FINE, "Removed empty xref dir:{0}",
627-
parent.getAbsolutePath());
628-
}
626+
PendingFileDeletion pending = new PendingFileDeletion(
627+
xrefFile.getAbsolutePath());
628+
completer.add(pending);
629629
}
630630

631631
private void removeHistoryFile(String path) {
@@ -647,8 +647,6 @@ private void removeFile(boolean removeHistory) throws IOException {
647647
}
648648

649649
writer.deleteDocuments(new Term(QueryBuilder.U, uidIter.term()));
650-
writer.prepareCommit();
651-
writer.commit();
652650

653651
removeXrefFile(path);
654652
if (removeHistory) {
@@ -1306,7 +1304,10 @@ public int hashCode() {
13061304
private Writer getXrefWriter(FileAnalyzer fa, String path) throws IOException {
13071305
Genre g = fa.getFactory().getGenre();
13081306
if (xrefDir != null && (g == Genre.PLAIN || g == Genre.XREFABLE)) {
1309-
File xrefFile = new File(xrefDir, path);
1307+
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
1308+
boolean compressed = env.isCompressXref();
1309+
File xrefFile = new File(xrefDir, path + (compressed ? ".gz" : ""));
1310+
13101311
// If mkdirs() returns false, the failure is most likely
13111312
// because the file already exists. But to check for the
13121313
// file first and only add it if it doesn't exists would
@@ -1315,14 +1316,17 @@ private Writer getXrefWriter(FileAnalyzer fa, String path) throws IOException {
13151316
assert xrefFile.getParentFile().exists();
13161317
}
13171318

1318-
RuntimeEnvironment env = RuntimeEnvironment.getInstance();
1319+
// Write to a pending file for later renaming.
1320+
String xrefAbs = xrefFile.getAbsolutePath();
1321+
File transientXref = new File(xrefAbs +
1322+
PendingFileCompleter.PENDING_EXTENSION);
1323+
PendingFileRenaming ren = new PendingFileRenaming(xrefAbs,
1324+
transientXref.getAbsolutePath());
1325+
completer.add(ren);
13191326

1320-
boolean compressed = env.isCompressXref();
1321-
File file = new File(xrefDir, path + (compressed ? ".gz" : ""));
1322-
return new BufferedWriter(new OutputStreamWriter(
1323-
compressed ?
1324-
new GZIPOutputStream(new FileOutputStream(file)) :
1325-
new FileOutputStream(file)));
1327+
return new BufferedWriter(new OutputStreamWriter(compressed ?
1328+
new GZIPOutputStream(new FileOutputStream(transientXref)) :
1329+
new FileOutputStream(transientXref)));
13261330
}
13271331

13281332
// no Xref for this analyzer
@@ -1345,4 +1349,26 @@ LockFactory pickLockFactory(RuntimeEnvironment env) {
13451349
return NoLockFactory.INSTANCE;
13461350
}
13471351
}
1352+
1353+
private void finishWriting() throws IOException {
1354+
boolean hasPendingCommit = false;
1355+
try {
1356+
writer.prepareCommit();
1357+
hasPendingCommit = true;
1358+
1359+
int n = completer.complete();
1360+
LOGGER.log(Level.FINE, "completed {0} file(s)", n);
1361+
1362+
// Just before commit(), reset the `hasPendingCommit' flag,
1363+
// since after commit() is called, there is no need for
1364+
// rollback() regardless of success.
1365+
hasPendingCommit = false;
1366+
writer.commit();
1367+
} catch (IOException e) {
1368+
if (hasPendingCommit) writer.rollback();
1369+
LOGGER.log(Level.WARNING,
1370+
"An error occured while finishing writer and completer", e);
1371+
throw e;
1372+
}
1373+
}
13481374
}

0 commit comments

Comments
 (0)