@@ -96,9 +96,17 @@ public class IndexDatabase {
96
96
97
97
private static final Logger LOGGER = LoggerFactory .getLogger (IndexDatabase .class );
98
98
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
+
99
106
private Project project ;
100
107
private FSDirectory indexDirectory ;
101
108
private IndexWriter writer ;
109
+ private PendingFileCompleter completer ;
102
110
private TermsEnum uidIter ;
103
111
private IgnoredNames ignoredNames ;
104
112
private Filter includedNames ;
@@ -377,14 +385,16 @@ public void update() throws IOException, HistoryException {
377
385
}
378
386
}
379
387
380
- IOException writerException = null ;
388
+ IOException finishingException = null ;
381
389
try {
382
390
Analyzer analyzer = AnalyzerGuru .getAnalyzer ();
383
391
IndexWriterConfig iwc = new IndexWriterConfig (analyzer );
384
392
iwc .setOpenMode (OpenMode .CREATE_OR_APPEND );
385
393
iwc .setRAMBufferSizeMB (env .getRamBufferSize ());
394
+ iwc .setMaxBufferedDeleteTerms (MAX_BUFFERED_DELETE_TERMS );
386
395
writer = new IndexWriter (indexDirectory , iwc );
387
396
writer .commit (); // to make sure index exists on the disk
397
+ completer = new PendingFileCompleter ();
388
398
389
399
if (directories .isEmpty ()) {
390
400
if (project == null ) {
@@ -451,20 +461,19 @@ public void update() throws IOException, HistoryException {
451
461
}
452
462
453
463
try {
454
- writer . commit ();
464
+ finishWriting ();
455
465
} catch (IOException e ) {
456
- writerException = e ;
457
- LOGGER .log (Level .WARNING ,
458
- "An error occured while committing writer" , e );
466
+ finishingException = e ;
459
467
}
460
468
} finally {
461
469
Ctags finishingCtags = ctags ;
462
470
ctags = null ;
463
471
472
+ completer = null ;
464
473
try {
465
474
if (writer != null ) writer .close ();
466
475
} catch (IOException e ) {
467
- if (writerException == null ) writerException = e ;
476
+ if (finishingException == null ) finishingException = e ;
468
477
LOGGER .log (Level .WARNING ,
469
478
"An error occured while closing writer" , e );
470
479
} finally {
@@ -484,7 +493,7 @@ public void update() throws IOException, HistoryException {
484
493
}
485
494
}
486
495
487
- if (writerException != null ) throw writerException ;
496
+ if (finishingException != null ) throw finishingException ;
488
497
489
498
if (!isInterrupted () && isDirty ()) {
490
499
if (env .isOptimizeDatabase ()) {
@@ -604,7 +613,7 @@ private void setDirty() {
604
613
}
605
614
606
615
/**
607
- * Remove xref file for given path
616
+ * Queue the removal of xref file for given path
608
617
* @param path path to file under source root
609
618
*/
610
619
private void removeXrefFile (String path ) {
@@ -614,18 +623,9 @@ private void removeXrefFile(String path) {
614
623
} else {
615
624
xrefFile = new File (xrefDir , path );
616
625
}
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 );
629
629
}
630
630
631
631
private void removeHistoryFile (String path ) {
@@ -647,8 +647,6 @@ private void removeFile(boolean removeHistory) throws IOException {
647
647
}
648
648
649
649
writer .deleteDocuments (new Term (QueryBuilder .U , uidIter .term ()));
650
- writer .prepareCommit ();
651
- writer .commit ();
652
650
653
651
removeXrefFile (path );
654
652
if (removeHistory ) {
@@ -1306,7 +1304,10 @@ public int hashCode() {
1306
1304
private Writer getXrefWriter (FileAnalyzer fa , String path ) throws IOException {
1307
1305
Genre g = fa .getFactory ().getGenre ();
1308
1306
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
+
1310
1311
// If mkdirs() returns false, the failure is most likely
1311
1312
// because the file already exists. But to check for the
1312
1313
// 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 {
1315
1316
assert xrefFile .getParentFile ().exists ();
1316
1317
}
1317
1318
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 );
1319
1326
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 )));
1326
1330
}
1327
1331
1328
1332
// no Xref for this analyzer
@@ -1345,4 +1349,26 @@ LockFactory pickLockFactory(RuntimeEnvironment env) {
1345
1349
return NoLockFactory .INSTANCE ;
1346
1350
}
1347
1351
}
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
+ }
1348
1374
}
0 commit comments