Avoid memory leaks

This commit is contained in:
Andrea Cavalli 2021-09-07 02:36:11 +02:00
parent f5d3474966
commit 66fa853272
3 changed files with 57 additions and 17 deletions

View File

@ -5,9 +5,13 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.SearcherManager;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CachedIndexSearcher {
private static final Logger logger = LoggerFactory.getLogger(CachedIndexSearcher.class);
private final IndexSearcher indexSearcher;
private final SearcherManager associatedSearcherManager;
private final Runnable afterFinalization;
@ -30,6 +34,7 @@ public class CachedIndexSearcher {
public void decUsage() throws IOException {
synchronized (this) {
if (usages > 0) {
usages--;
if (mustClose()) {
try {
@ -40,9 +45,11 @@ public class CachedIndexSearcher {
}
}
}
}
public void removeFromCache() throws IOException {
synchronized (this) {
if (inCache) {
inCache = false;
if (mustClose()) {
try {
@ -53,6 +60,7 @@ public class CachedIndexSearcher {
}
}
}
}
private void close() throws IOException {
if (associatedSearcherManager != null) {
@ -71,4 +79,17 @@ public class CachedIndexSearcher {
public IndexSearcher getIndexSearcher() {
return indexSearcher;
}
@Override
protected void finalize() throws Throwable {
if (usages > 0) {
logger.error("A cached index searcher has been garbage collected, but "
+ usages + " usages have not been released");
}
if (inCache) {
logger.error("A cached index searcher has been garbage collected, but it's marked"
+ " as still actively cached");
}
super.finalize();
}
}

View File

@ -7,6 +7,7 @@ import it.cavallium.dbengine.database.LLSnapshot;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.function.Function;
@ -184,15 +185,31 @@ public class CachedIndexSearcherManager {
public Mono<Void> close() {
return Mono
.fromRunnable(this.closeRequested::tryEmitEmpty)
.fromRunnable(() -> {
logger.info("Closing IndexSearcherManager...");
this.closeRequested.tryEmitEmpty();
})
.then(refresherClosed.asMono())
.then(Mono.fromRunnable(() -> {
logger.info("Closed IndexSearcherManager");
logger.info("Closing refreshes...");
if (!activeRefreshes.isTerminated()) {
activeRefreshes.arriveAndAwaitAdvance();
try {
activeRefreshes.awaitAdvanceInterruptibly(activeRefreshes.arrive(), 15, TimeUnit.SECONDS);
} catch (Exception ex) {
logger.error("Failed to terminate active refreshes", ex);
}
}
logger.info("Closed refreshes...");
logger.info("Closing active searchers...");
if (!activeSearchers.isTerminated()) {
activeSearchers.arriveAndAwaitAdvance();
try {
activeSearchers.awaitAdvanceInterruptibly(activeSearchers.arrive(), 15, TimeUnit.SECONDS);
} catch (Exception ex) {
logger.error("Failed to terminate active searchers", ex);
}
}
logger.info("Closed active searchers");
cachedSnapshotSearchers.invalidateAll();
cachedSnapshotSearchers.cleanUp();
}));

View File

@ -448,18 +448,20 @@ public class LLLocalLuceneIndex implements LLLuceneIndex {
public Mono<Void> close() {
return Mono
.<Void>fromCallable(() -> {
logger.debug("Closing IndexWriter...");
logger.info("Waiting IndexWriter tasks...");
activeTasks.arriveAndAwaitAdvance();
logger.info("IndexWriter tasks ended");
return null;
})
.subscribeOn(luceneHeavyTasksScheduler)
.then(searcherManager.close())
.then(Mono.<Void>fromCallable(() -> {
logger.info("Closing IndexWriter...");
//noinspection BlockingMethodInNonBlockingContext
indexWriter.close();
//noinspection BlockingMethodInNonBlockingContext
directory.close();
logger.debug("IndexWriter closed");
logger.info("IndexWriter closed");
return null;
}).subscribeOn(luceneHeavyTasksScheduler));
}