Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LUCENE-10369: Move DelegatingCacheHelper to FilterDirectoryReader #596

Merged
merged 12 commits into from
Jan 11, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,37 @@ protected void doClose() throws IOException {
public DirectoryReader getDelegate() {
return in;
}

/**
* A DelegatingCacheHelper is a CacheHelper specialization for implementing long-lived caching
* behaviour for FilterDirectoryReader subclasses. It uses a unique CacheKey for the purpose of
* implementing the onClose listener delegation for the reader.
*/
protected static class DelegatingCacheHelper implements CacheHelper {
private final CacheHelper delegate;
private final CacheKey cacheKey = new CacheKey();

/**
* Create a new DelegatingCacheHelper that delegates the cache onClose listener to another
* CacheHelper, but with its own unique CacheKey.
*
* @param delegate the CacheHelper to delegate the close listener to
*/
protected DelegatingCacheHelper(CacheHelper delegate) {
this.delegate = delegate;
}

@Override
public CacheKey getKey() {
return cacheKey;
}

@Override
public void addClosedListener(ClosedListener listener) {
// here we wrap the listener and call it with our cache key
// this is important since this key will be used to cache the reader and otherwise we won't
// free caches etc.
delegate.addClosedListener(unused -> listener.onClose(cacheKey));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -259,26 +259,4 @@ public CacheHelper getReaderCacheHelper() {
return readerCacheHelper;
}
}

private static class DelegatingCacheHelper implements CacheHelper {
private final CacheHelper delegate;
private final CacheKey cacheKey = new CacheKey();

public DelegatingCacheHelper(CacheHelper delegate) {
this.delegate = delegate;
}

@Override
public CacheKey getKey() {
return cacheKey;
}

@Override
public void addClosedListener(ClosedListener listener) {
// here we wrap the listener and call it with our cache key
// this is important since this key will be used to cache the reader and otherwise we won't
// free caches etc.
delegate.addClosedListener(unused -> listener.onClose(cacheKey));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.FilterDirectoryReader.SubReaderWrapper;
Expand Down Expand Up @@ -143,4 +144,57 @@ public void testFilterDirectoryReaderNumDocsIsLazy() throws IOException {
directoryReader.close();
dir.close();
}

private static class DummyLastingFilterDirectoryReader extends FilterDirectoryReader {
private final CacheHelper cacheHelper;

public DummyLastingFilterDirectoryReader(DirectoryReader in) throws IOException {
super(in, new DummySubReaderWrapper());
cacheHelper =
(in.getReaderCacheHelper() == null)
? null
: new DelegatingCacheHelper(in.getReaderCacheHelper());
}

@Override
protected DirectoryReader doWrapDirectoryReader(DirectoryReader in) throws IOException {
return new DummyFilterDirectoryReader(in);
}

@Override
public CacheHelper getReaderCacheHelper() {
return cacheHelper;
}
}

public void testDelegatingCacheHelper() throws IOException {
Directory dir = newDirectory();
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig());
w.addDocument(new Document());

DirectoryReader reader = DirectoryReader.open(w);
DirectoryReader wrapped = new DummyLastingFilterDirectoryReader(reader);

assertNotEquals(reader.getReaderCacheHelper(), wrapped.getReaderCacheHelper());
assertNotEquals(
reader.getReaderCacheHelper().getKey(), wrapped.getReaderCacheHelper().getKey());

AtomicInteger closeCalledCounter = new AtomicInteger(0);

wrapped
.getReaderCacheHelper()
.addClosedListener(
key -> {
closeCalledCounter.incrementAndGet();
assertSame(key, wrapped.getReaderCacheHelper().getKey());
});

reader.close();
assertEquals(1, closeCalledCounter.get());
wrapped.close();
assertEquals(1, closeCalledCounter.get());

w.close();
dir.close();
}
}